Kotlin 入门(二):高级用法

习惯用法

data class

我们在用java开发项目的时候会编写很多java bean类,而data class 可以帮助我们简化这一过程,在java文件编译成class文件的过程中,帮助我们重载里面的一些方法。
类提供以下功能:
1.所有属性的 getters (对于 var 定义的还有 setters)
2.equals()
3.hashCode()
4.toString()
5.copy()
6.所有属性的 component1() 、 component2() ……等等

data class Customer(val name: String, val email: String)

可以把所有java bean的类放在一个文件中,一句话就解决了,非常便捷,虽然,data class 给了我们很大的便捷之处,但是如果我们用gson来解析解析json数据生成data class对象还有一些问题,会在另一篇文章讲到

解构声明

有时把一个对象解构成很多变量会很方便

val (name,  age)    =   person

一个解构声明会被编译成以下代码:

val name    =   person.component1()
val age =   person.component2()

密封类

密封类用来表示受限的类继承结构:当一个值为有限集中的 类型、而不能有任何其他类型 时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量 只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。
要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以 有子类,但是 所有子类都必须在与密封类自身相同的文件中声明:

扩展函数

声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。 下面 代码为 MutableList<Int> 添加一个 swap 函数:

fun MutableList<Int>.swap(index1:   Int,    index2: Int)    {
        val tmp =   this[index1]    //  “this”对应该列表             
        this[index1]    =   this[index2]        
        this[index2]    =   tmp 
}

扩展不能真正的修改他们所扩展的类。通过定义一个扩展,你并没有在一个类中插入新成 员, 仅仅是可以通过该类型的变量用点表达式去调用这个新函数

扩展属性

val <T> List<T>.lastIndex:  Int             
get()   =   size    -   1

泛型

与 Java 类似,Kotlin 中的类也可以有类型参数:

class   Box<T>(t:   T)  {
var value   =   t 
}

但是如果类型参数可以推断出来,例如从构造函数的参数或者从其他途径,允许省略类型参 数:

val box =   Box(1)  
//  1   具有类型    Int,所以编译器知道我们说的是    Box<Int>。

型变:
首先,Java 中的泛型是不型变的,这意 味着 List<String> 并不是 List<Object> 的子类型。 为什么这样? 如果 List 不是不型变 的,它就没 比 Java 的数组好到哪去,因为如下代码会通过编译然后导致运行时异常:

//  
Java List<String>   strs    =   new ArrayList<String>();
List<Object>    objs    =   strs;   //!!!即将来临的问题的原因就在这里。Java    禁止这样!
objs.add(1);    //  这里我们把一个整数放入一个字符串列表 
String s    =   strs.get(0);    //  !!! ClassCastException:无法将整数转换为字符串

kotlin中引入了in和out关键字。
假设有一个泛型接口 Source<T> ,该接口中不存在任何以 T 作为参数的方法,只是方法返 回 T 类型值:

interface   Source<T>{
T   nextT(); 
}

那么,在 Source <Object> 类型的变量中存储 Source <String> 实例的引用是极为安全的 ,因为String是Object的子类。但是 Java 并不知道这一点,并且仍然禁止这样操作:

Java 
void    demo(Source<String> strs)   {
Source<Object>  objects =   strs;
    //  !!!在    Java    中不允许        //  …… 
}

为了修正这一点,我们必须声明对象的类型为Source<? extends Object>
在 Kotlin 中,有一种方法向编译器解释这种情况。这称为声明处型变:我们可以标注 Source 的类型参数 T 来确保它仅从 Source<T> 成员中返回(生产),并从不被消费。 为此,我们 提供 out 修饰符:

abstract    class   Source<out  T>  {
abstract    fun nextT():    T 
}


fun demo(strs:  Source<String>) {
val objects:    Source<Any> =   strs    
//  这个没问题,因为    T   是一个 out-参数
……
 }

一般原则是:当一个类 C 的类型参数 T 被声明为 out 时,它就只能出现在 C 的成员的输 出-位置,但回报是 C<Base> 可以安全地作为 C<Derived> 的超类。
另外除了 out,Kotlin 又补充了一个型变注释:in。它使得一个类型参数逆变:只可以被消费 而不可以 被生产。逆变类的一个很好的例子是 Comparable :

abstract    class   Comparable<in   T>  {
abstract    fun compareTo(other:    T): Int 
}

fun demo(x: Comparable<Number>) {
x.compareTo(1.0)    //  1.0 拥有类型    Double,它是   Number  的子类型                //  因此,我们可以将    x   赋给类型为   Comparable  <Double>    的变量
val y:  Comparable<Double>  =   x   //  OK!
 }

理解为什么这个技巧能够工作的关键相当简单:如果只能从集合中获取项目,那么使用 String 的集合, 并且从其中读取 Object 也没问题 。反过来,如果只能向集合中 放入 项 目,就可以用 Object 集合并向其中放入 String

星投影
有时你想说,你对类型参数一无所知,但仍然希望以安全的方式使用它。 这里的安全方式是 定义泛型类型的这种投影
Kotlin 为此提供了所谓的星投影语法:
1.对于 Foo <out T> ,其中 T 是一个具有上界 TUpper 的协变类型参数, Foo <> 等价 于 Foo <out TUpper> 。 这意味着当 T 未知时,你可以安全地从 Foo <> 读取 TUpper 的值。
2.对于 Foo <in T> ,其中 T 是一个逆变类型参数, Foo <> 等价于 Foo <in Nothing> 。 这意味着当 T 未知时,没有什么可以以安全的方式写入 Foo <> 。
3.对于 Foo <T> ,其中 T 是一个具有上界 TUpper 的不型变类型参数, Foo<*> 对于读 取值时等价于 Foo<out TUpper> 而对于写值时等价于 Foo<in Nothing> 。

泛型约束:
最常见的约束类型是与 Java 的 extends 关键字对应的 上界:

fun <T  :   Comparable<T>>  sort(list:  List<T>)    {               //  …… 
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • 一. Java基础部分.................................................
    wy_sure阅读 3,785评论 0 11
  • http://liuxing.info/2017/06/30/Spring%20AMQP%E4%B8%AD%E6%...
    sherlock_6981阅读 15,861评论 2 11
  • JAVA面试题 1、作用域public,private,protected,以及不写时的区别答:区别如下:作用域 ...
    JA尐白阅读 1,143评论 1 0
  • 我的生活和幻想是完美!的我喜欢幻想我喜欢编鬼故事把他们吓的半死,我是一位四年级的小学生,爸爸妈妈想让我看点成...
    7叶草我爱你阅读 88评论 1 2
  • 【482】每日步行第482天 打卡虽然结束了,但我必须将这种习惯一直保持下去,所以我给自己提了个要求:每天更新字数...
    字雕朽木阅读 463评论 7 6