声明泛型

泛型可以大大提高程序的动态性和灵活性。在Kotlin中声明泛型和Java类似:

class MyNumber<T>(var n: T)
//传入参数,如果类型可以推断出来,则可以省略
MyNumber<Int>(1)
MyNumber(1) //Int可以不写
MyNumber<Float>(1.2f) //Float也可以不写

泛型赋值

来看一个例子,这个例子说明了父类泛型并不能直接接收子类泛型:

var n1 = MyNumber<Int>(1)
var n2: MyNumber<Any> = n1 //编译报错,尽管Any是Int的父类,Any相当于Java的Object

上面的例子在Java中也是无法编译通过的,在Java中需要这样做:

ANumber<? extends Object> n2 = n1;

Kotlin提供了out关键字,out T表示可以接收T以及T的子类:

var n1 = MyNumber<Int>(1)
var n2: MyNumber<out Any> = n1 //编译通过

再来看一个方法:

fun fill(dest: ArrayList<String>, value: String){
    dest.add(value)
}
fill(arrayListOf<String>(), "22") 
fill(arrayListOf<CharSequence>(), "22") //编译出错,尽管String是CharSequence的实现类

上面的方法将一个String装入ArrayList<String>,但有时候我们希望fill方法也能接收泛型是String父类的集合,此时可以使用in String,表示接收String以及它的父类:

fun fill(dest: ArrayList<in String>, value: String){
    dest.add(value)
}
fill(arrayListOf<CharSequence>(), "22") //编译通过

in关键字对应了Java中的ArrayList<? super String>

泛型通配符

在Java中如果我们希望一个泛型可以接收所有类型,一般可以使用通配符?

ANumber<?> n2 = new ANumber<Integer>(1);
n2 = new ANumber<Float>(1.2f);

在Kotlin中用*表示通配符:

var n2: MyNumber<*> = MyNumber<Int>(1)
n2 = MyNumber(1000L)

泛型函数

除了类上面可以声明泛型,函数也可以声明泛型:

fun <T, R> foo(t: T, r: R){
}
//调用函数
foo<Int, String>(1, "2")
更新时间: 4/25/2019, 4:39:18 PM