Kotlin学习之泛型(协变和逆变实战)

 首先看看在Java中协变和逆变的栗子

public class Animal {
}

public class Cat extends Animal{
}

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main4);
       
   List<Cat> cats = new ArrayList<>();
   List<? extends Animal> animals= cats;
}

这样是可以赋值成功的 

 这样是编译失败的,因为animal的类型是List<Animal>或者List<Animal的子类>,如果把new Cat放进去了,那么把取出来的时候到底是不是Cat类型取决于声明的泛型类型,这里根本不知道真正的类型是什么,只知道是List<Animal>或者List<Animal的子类>,那么可能是Cat 也可能是Dog。所以协变的特点是就是读取操作,写入的操作是不被允许的。那么逆变是可以写入,但是不能读取。

下一个栗子:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main4);
       
   List<Animal> animals1 = new ArrayList<>();
   List<? super Animal> animals2 = animals1;
}

animals1 的类型是 List<Animal>,animals2的类型是List<Animal>或者List<Animal的父类型一直到Object>

animals2里面添加new Cat()是可以的,Cat是位于Animal下面的为什么可以?

根据多态,Cat就是Animal,所以这种操作时可以的。如果我读取呢?

不兼容类型,不允许读取,因为animals2的类型是List<Animal>或者List<Animal的父类型一直到Object>都可以,赋值给Animal,显然是不允许的。

Java中 的数组是天然支持协变的,解释下这句话:

List<String> 和List<Object>是不能直接赋值的,但是对于数组来说呢,比如:

   Object[] objects = new String[]{"hello","world"};

这样做是可以的。将String类型的数组赋值给Object类型的数组,是可以的,这是协变。但是是有问题的:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main5);
        Object[] objects = new String[]{"hello","world"};
        objects[0] = new Object();//编译通过,运行时报数组存储异常
    }

接下去看下Kotlin

class TestClass<A>(private val value: A) {
    
    fun getValue(): A {
        return this.value
    }
}

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
        val testClass = TestClass<String>("hell world")
        val result = testClass.getValue()
    }

这样写是没有任何问题的,定义好什么类型,就按照泛型来使用

class TestClass<out T>(private val value: T) {

    fun getValue(): T {
        return this.value
    }
}


 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
        val testClass = TestClass<String>("hell world")
        var myClass: TestClass<Any> = testClass
    }

这个是Kotlin的协变。类似于Java中的这种情况

List<String> list2 = new ArrayList();
List<? extends Object> list = list2;
class TestClass<in T> {

    fun toString(value: T): String {
        return value.toString()
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
        val testClass = TestClass<Number>()
        var myClass: TestClass<Int> = testClass//父类型赋给子类型
    }

这个是Kotlin的逆变。类似于Java中写这种情况

List<Object> list = new ArrayList();
List<? super String> list2 = list;

猜你喜欢

转载自blog.csdn.net/jingerlovexiaojie/article/details/107047333