在使用kotlin的范型时,发现它比java多了两个关键字out
和in
。在java的范型中常用的关键字是extends和super,所以我在想out和in和它们之间是否存在某些关系。关于java范型中的extends和super使用,可以参考Java范型的上限约束和下限约束。
要说范型还是得从java的范型说起,我们知道java中的范型在编译之后就没有了,也是就是常提到的类型擦除,比如说下面这段代码。
在编译之后就变成了这样。
既然这样,那为什么还要用范型呢?为了保证类型安全,通过范型约束,我们可以在编译期间提前发现类型安全问题,而不是在运行时报错。比如说,如果没有范型,这段代码是可以编译通过的。
但是在运行时会发生ClassCastException,如果使用了范型进行约束,那么在编译时就会报错,让开发者及时发现错误。
但是类型约束也导致了一些问题,比如说我们有一个自定义的列表ZXList,和一个数据类Parent和Child。
现在有一个Parent类型和一个Child类型的ZXList,我们想让两个ZXList合并,很自然地使用addAll方法,但是却发现编译不通过。
这就不符合正常逻辑了,按道理Child类型类型应该是能够兼容Parent类型的,但是上面这样addAll定义就是不能兼容,如果需要实现兼容,我们需要extends
关键字把addAll方法定义改成这样。
这样的意思是addAll里面的ZXList的范型类型只要是继承自T
类型即可。而在kotlin中这些写法就变成了使用out
关键字。
以上就是out
关键字的作用之一。我们知道按道理childList是兼容parentList的,但是我们却不能把childList赋值给parentList,即下面的java代码编译是无法通过的。
但是在kotlin中,通过out关键字这也是可以实现的。
在java的范型中super这个关键字,最经典的应用示例就是List.sort(Comparator<? super E> c),还是以ZXList为例说明,假设ZXList也有一个sort方法,定义如下。
另外有Animals、Dog和Cat三个类,定义如下。
现在有两个ZXList分别是ZXList<Dog>和ZXList<Cat>,我们想让两个列表都通过age字段进行排序。
运行后发现编译出错,dogList和catList不能使用Comparator<Animal>
进行排序,这明显也不符合正常逻辑,Dog和Cat都是继承自Animal,为什么就不能使用Comparator<Animal>
排序呢?其实也是有办法的,那就是使用super
关键字,把ZXList的sort方法定义改成
在kotlin中要实现这个效果就是使用in
关键字,代码如下
kotlin中的out和in关键字主要用于强化范型的使用,kotlin中的<out T>
相当于java中的<? extends T>
,而<in T>
就相当于<? super T>
,但是in
和out
关键字的功能要更强大一些,另外要注意的是java中的范型上限用的也是extends
关键字,比如<T extends Animal>
,kotlin中范型的上限用的是:
,比如T : Animal
。