从Java到Kotlin(四)

对象与泛型

目录

1.对象

1.1 匿名类与对象

1.2 静态类成员与伴生对象

2.泛型

2.1 型变

2.2 类型投影

2.3 泛型函数

2.4 泛型约束

1.对象

1.1 匿名类与对象表达式

Java中有匿名类这个概念,指的是在创建类时无需指定类的名字。在Kotlin中也有功能相似的“匿名类”,叫做对象,举个例子:

Java匿名类

Kotlin实现上面的代码,要用关键字object创建一个继承自某个(或某些)类型的匿名类的对象,如下所示:

对象object还可以实现接口,如下所示:

对象和类一样,只能有一个父类,但可以实现多个接口,多个超类型跟在冒号:后面用逗号分隔。

如果只想建立一个对象,不继承任何类,不实现任何接口,可以这样写:

运行代码,查看结果:

请注意,匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的返回类型或者用作公有属性的类型,那么该函数或属性的实际类型会是匿名对象声明的超类型,如果你没有声明任何超类型,就会是 Any。在匿名对象中添加的成员将无法访问。如下所示:

内部类访问作用域内的变量

就像 Java 匿名内部类一样,Java可以用final声明变量,使匿名内部类可以使用来自包含它的作用域的变量。如下所示:

而Kotlin在匿名对象中可以任意访问或修改变量age,如下所示:

运行代码,查看结果:

1.2 伴生对象

Java中有静态类成员,而Kotlin中没有,要实现像静态类成员的功能,就要用到伴生对象。

Java静态成员:

Kotlin类内部的对象声明可以用 companion 关键字标记:

2.泛型

2.1型变

Java泛型

对应的Kotlin泛型

可以看出Java跟Kotlin定义泛型的方法都是差不多的,不同的是Java中的泛型有通配符,而Kotlin没有。举个例子:

Java编译器不认为List是List的子类,所以编译不通过。那我们换种写法:

为什么调用addAll()方法就能编译通过呢,看一下他的源码:

Java泛型提供了问号通配符,上面的代表此方法接受 E 或者 E 的 一些子类型对象的集合。所以可以通过addAll()方法把List赋值给List。

Kotlin的泛型没有提供通配符,取而代之的是和修饰符。先举个例子:

(红色波浪线标记处为编译错误)

(红色波浪线标记处为编译错误)

对比上面两段代码可以看出,用out来修饰T,只能消费T类型,不能返回T类型;

用in来修饰T,只能返回T类型,不能消费T类型。简单来说就是 in 是消费者, out 是生产者。

2.2 类型投影

上面说到了和修饰符,如果我们不用他们来修饰泛型,会出现这种情况:

(红色波浪线标记处为编译错误)

编译不通过,因为Array对于类型T是不可变的,所以Box和Box谁也不是谁的子类型,所以编译不通过。对于这种情况,我们还是可以用和修饰符来解决,但不是用来修饰Box,如下所示:

上面的解决方式叫做类型投影,Box相当于 Java 的 Box、Box相当于 Java 的 Box。

2.3 泛型函数

不仅类可以有类型参数。函数也可以有。类型参数要放在函数名称之前:

类似于Java的泛型方法:

2.4 泛型约束

泛型约束能够限制泛型参数允许使用的类型,如下所示:

Kotlin代码

上述代码把泛型参数允许使用的类型限制为 List

Java中也有类似的泛型约束,对应的代码如下:

如果没有指定泛型约束,Kotlin的泛型参数默认类型上界是Any,Java的泛型参数默认类型上界是Object

总结

本篇文章对比了Java匿名类、静态类与Kotlin对象的写法和两种语言中对泛型的使用。相对来说,Kotlin还是在Java的基础上作了一些改进,增加了一些语法糖,更灵活也更安全。

参考文献:

Kotlin语言中文站、《Kotlin程序开发入门精要》

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180211G1771F00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券