Java的泛型比较弱,如下面代码
// Java
List<String> strs = new ArrayList<String>();
List<Object> objs = strs; // !!! The cause of the upcoming problem sits here. Java prohibits this!
objs.add(1); // Here we put an Integer into a list of Strings
String s = strs.get(0); // !!! ClassCastException: Cannot cast Integer to String
//List<String>不能被cast成List<Object>
所以Java引入了通配符的概念
// Java
interface Collection<E> ... {
void addAll(Collection<? extends E> items);
}
kotlin为了解决这个泛型问题,引入了C#中的in/out机制。
abstract class Source<out T> {
abstract fun nextT(): T
}
fun demo(strs: Source<String>) {
val objects: Source<Any> = strs // This is OK, since T is an out-parameter
// ...
}
//out:相当于<? extends T>,那么使用out修饰泛型T后,Source<String>可以被cast成Source<Any>
abstract class Comparable<in T> {
abstract fun compareTo(other: T): Int
}
fun demo(x: Comparable<Number>) {
x.compareTo(1.0) // 1.0 has type Double, which is a subtype of Number
// Thus, we can assign x to a variable of type Comparable<Double>
val y: Comparable<Double> = x // OK!
}
//in:相当于<? super T>,所以泛型T被in修饰后,Comparable<Number>可以被cast被Comparable<Double>
当你不知道具体类型时可以使用*配符
Function<*, String> means Function<in Nothing, String>
Function<Int, *> means Function<Int, out Any?>
Function<*, *> means Function<in Nothing, out Any?>
泛型理解起来会比较复杂,需要自己写代码理解。