为了理清楚泛型的通配符和上下界的作用,并为了Kotlin的泛型中的关键字inout的理解,在此用小demo重新梳理一遍对泛型的理解。

demo

  1. public class Example {
  2. //程序入口
  3. public static void main(String[] args) {
  4. Source<? extends Number> sourceOfNumber = new Source<>();
  5. Number params = sourceOfNumber.getParams();//get()方法,通过编译
  6. sourceOfNumber.setParams(1);//①set()方法,不通过编译
  7. Source<? super Integer> sourceOfParentOfInt = new Source<>();
  8. sourceOfParentOfInt.setParams(new Integer(1));//set()方法,通过编译
  9. Number i = sourceOfParentOfInt.getParams();//②get()方法,不通过编译
  10. }
  11. //包装对象
  12. private static class Source<T> {
  13. private T params;
  14. public T getParams() {
  15. return params;
  16. }
  17. public void setParams(T params) {
  18. this.params = params;
  19. }
  20. }
  21. }

以下来自《疯狂Kotlin讲义》并结合上述代码的理解。

通配符下界Source<? super Integer>

在这里,T就是? super Integer。由于Source<T>中的泛型一定是Integer的父类,因此程序总是可以向Source对象传入Integer值。但从Source<T>中取出对象是不安全的,因为无法预测到取出的是Number对象还是Object对象,即无法判断demo中的sourceOfParentOfInt引用的对象实际是Source<Number>还是Source<Object>

因此往对象中设置值总是安全的,取出值总是不安全的。

通配符上界Source<? extends Integer>

在这里,T就是? extends Number。由于Source<T>中的泛型一定是Number的子类,因此程序从Source对象中取出的T一定是Number的子类,即可以用Number来引用。但是向其中传入对象是不安全的,因为你不能确定demo中的sourceOfNumber引用的到底是Source<Float>还是Source<Integer>,如果是引用了Source<Float>对象,而你往里面传了一个Integer,那么程序就出错了。

因此从对象中取出值是安全的,但是往对象中设置值是不安全的。