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?>
泛型理解起來會比較複雜,需要自己寫代碼理解。