协变out(? extend E),逆变in(? super E)在Kotlin和java的区别练习

在Kotlin

//泛型 generics 变量类型的参数化
//创建一个var T,将构造变量T传入属性T
class MyGeneric<T>(t: T) {
    var variable: T
//初始化变量t(必须)
    init {
        this.variable = t
    }
}
class MyClass2<out T, in M>(t: T, m: M) {
    //创建有2变量数据类型的泛型类
    //out代表生产者,只能读取,类似java的<? extend E>协变
    //in代表消费者,只能写入,类似java的<? super E>逆变,String看你所需要的类型
    private var t: T
    private var m: M
    //初始化var t,m from out t,in m
    init {
        this.t = t
        this.m = m
    }
//    协程 out t只能读取,so 只能get()
    fun get(): T = this.t
//    逆程 in  m只能写入,so 只能 set方法
    fun set(m: M) {
        this.m = m
        println(m is Number)
    }
}
//这个Test需要关注的是协变的泛型范围
fun myTest(myClass: MyClass2<String, Number>) {
    //注意 String写入MyClass2是读取,<? extend object>协变
    //Number读取MyClass是写入,<? super String>逆变
    val myObject: MyClass2<Any, Int> = myClass
    println(myObject.get())//读取Any  写入都是Number
}
fun main(args: Array<String>) {
//    创建MyGeneric<String>的泛型的类
//   类型推断 尖括号可以省略
    val myGeneric2 = MyGeneric("hello world")
    println(myGeneric2.variable)
    println("---------------------------")
    val myClass = MyClass2<String, Number>("abc", 3.2)
    myTest(myClass)
}


output:
hello world
---------------------------
abc

在java

public class MyTest {
    public static void main(String[] args) {
//        List<String> list = new ArrayList<String>();
//        //报错代码
//        List<Object> list2 = list;
//        list2.add(3);
//        String str = list2.get(0);
        /*--------------PECS Producer Extends,Consumer Super------------*/
        List<Cat> cats = new ArrayList<Cat>();
        //放入Animal或者Animal的子类 协变
        List<? extends Animal> animals = cats;

        //不能写入 因为并不能知道animals列表具体的是List<Cat>还是List<Dog>只能知道是Animal或者其子类的List
        //animals.add(new Cat());


        List<Animal> animals1 = new ArrayList<>();
        //放入Animal或者Animal父类 写入的时候 父类转子类所以可以写入
        List<? super Animal> contravariant = animals1;
        contravariant.add(new Animal());
        contravariant.add(new Cat());//多态
        contravariant.add(new Dog());//多态
        //contravariant.add(new Object());//实际类型是Animal

        //这样可行
        List<Object> list = new ArrayList<>();
        list.add(new Object());
        List<? super Animal> contravariant1 = list;
        //contravariant1.add(new Object());

        //不能读取 只能知道是Animal的父类 不知道是Object 还是其他的 父类转子类是错误的
        //Animal animal = contravariant.get(0);

        /*-----------------------------------------*/
        //类型是Object 指向String数组,Java数组支持协变逆变,不过会出现一些问题
        Object[] objs = new String[]{"aaa", "bbb"}; //协变
        objs[0] = new Object();//错误做法把String元素改成了Object对象
    }
}

class Animal {

}

class Cat extends Animal {

}

class Dog extends Animal {

}
output:

协变逆变区别

public class xiebiannibian {
    public static void main(String[] args) {
        // 协变(covariant)和逆变(controversial)
        List<Object>
        List<String>
        //List<String> 不是 List<Object>的子类 List不支持协变

        List<String> list = new ArrayList();
        List<Object> list2 = list; //编译失败

        list2.add (new Date( ) );
        String str = list.get(0);

        //通配符的出现 解决上面问题
        List<? extends Object> list ...


        interface Collection<E> {
            void addAll(Collection<E> items)
        }

        interface Collection<E> {
            //错误做法
            void addAll(Collection<E> items)

            //java库 实际上是这样的
            //可以随意的把集合内容当作E来读取而不当作实际类型来读取
            // 而不能随意的写入修改内容 ,因为可以添加E的任意子类实例 但是不知道实际类型
            boolean addAll(Collection<? extends E> c);
            //Number或其子类
        }

        void copyAll(Collection<Object> to, Collection<String> from) {
            to.addAll(from)
        }

        //被限制了上界 只能读取 读取到的当作E 叫做协变  生产者
       // Collection<String> 就是Collection<? extends Object>的子类型 而不是Collection<Object>;

        //限定了只能放入String的父类 只能写入成String 是类型安全的 叫做逆变 消费者
       //List<? super String>
       //List<? super E>

        List<? super Number> list001 = new ArrayList<Number>();
        //Object或其他Number的父类
        list001.add(new Integer(3));
        list001.add(new Float(2.1));


        List<? super Number> list002 = new ArrayList<Object>();
        list002.add(3);
        list002.add(1);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值