• Java VS kotlin 泛型


    java 虚拟机泛型实现(伪泛型)

    Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此,对于运行期的Java语言来说,ArrayList<int>与ArrayList<String>就是同一个类,所以泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型称为伪泛型。

    Java 通配符

    A<String> aString= new A();
    A<? extends Object>  aInteger = aString;
    
    A<Object> aObject = new A();
    A<? super String> aSuper = aObject;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    获取泛型type

    通过匿名内部类获取父类的元数据定义,来获取type,获取泛型的具体类型。

    static class A<T> {
            T a;
        }
        
        public static final void main(String[] args) {
            ArrayList list = new ArrayList<String>(){};
            A a = new A<Integer>(){};
            System.out.println(a.getClass().getGenericSuperclass());
            System.out.println(list.getClass().getGenericSuperclass());
    
            ParameterizedType parameterizedType = (ParameterizedType)a.getClass().getGenericSuperclass();
            Type type = parameterizedType.getActualTypeArguments()[0];
            System.out.println("A类型变量泛型 type: "+type);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    协变逆变 - 生产者消费者

    1. 生产者->协变->kotlin: out->java: <? extends Object>(上界通配符)
    2. 消费者->逆变->kotlin: in ->java: <? super String>(下界通配符)
    3. PECS(producers extends, consumers super)
      生产者适合out,<? extends Object>因为编译器不知道具体类型是什么子类,无法赋值,但是可以取出来作为Object
      消费者适合in,<? super String>因为任何父类都可以作为输入,但是无法取出赋值给具体的类型
    4. 赋值语句左边类型必须大于右边类型
    5. 函数返回类型必须大于函数体内真实返回对象类型

    实战

    java 协变逆变

    	static class Fruit{}
        static class Apple extends Fruit{
            @NonNull
            @Override
            public String toString() {
                return "Apple";
            }
        }
        // 上界通配符只适合 out 数据 ,通过get访问数据
        List<? extends Fruit> fruitsOut = apples;
        Fruit fruit = fruitsOut.get(0);// Fruit 类型范围大于get获取的类型
        // fruitsOut.add(new Apple()); // 无法确认添加的lei'xing
    
    
        // 下界通配符只适合in 数据, 通过add 添加数据
        List<? super Fruit> fruitsIn = new ArrayList<>();
        fruitsIn.add(new Apple());// fruitsIn类型范围大于Apple
    
        // Fruit object = fruitsIn.get(0); // 报错无法识别get获取到类型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    kotlin 协变逆变

    interface Source<out T> {
        fun nextT(): T
    }
    
    fun demo(strs: Source<String>) {
        val objects: Source<Any> = strs // 这个没问题,因为 T 是一个 out-参数
    }
    
    interface Comparable<in T> {
        fun compareTo(other: T): Int
    }
    
    fun demo(x: Comparable<Number>) {
        x.compareTo(1.0) // 1.0 拥有类型 Double,它是 Number 的子类型
        // 因此,我们可以将 x 赋给类型为 Comparable <Double> 的变量
        val y: Comparable<Double> = x // OK!
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    参考:

    Java泛型的协变、逆变和不变
    深入理解Kotlin中的泛型(协变、逆变)
    Java泛型的定义和使用详解
    Java泛型的协变、逆变和不变
    PECS(Producer Extends Consumer Super)原则
    kotlin官方

  • 相关阅读:
    Hive总结
    MySQL 变量的详细讲解
    Redis篇---第二篇
    当苹果开发者发现自己的产品被抄袭时,该怎么做?
    黑马Java热门面试题微服务(八)
    【微服务|OpenFeign】openfeign的超时时间
    强化学习从基础到进阶-案例与实践[4.2]:深度Q网络DQN-Cart pole游戏展示
    lambda的使用案例(1)
    玩转gRPC—不同编程语言间通信
    基于SSM的旅游景点购票管理系统
  • 原文地址:https://blog.csdn.net/baidu_16668271/article/details/125624621