泛型之不变、协变、逆变

本文介绍了Java和Kotlin中的泛型概念,包括其作用、为什么在编译后要做泛型擦出。讨论了泛型的不变性、协变性和逆变性,并给出了具体的示例,展示了它们在实际编程中的应用场景,如数组和集合类型的使用。同时,文章通过代码展示了如何在Kotlin中使用out关键字实现协变。

什么是泛型

早期在java1.5之前,java集合类是没有泛型的、集合内存储的对象都是object。这就导致了几个问题。
1.存储的元素取出来、需要类型强制转换、而且不能保证其准确性、如下图,改元素第一个需要转换成String 类型、第二个元素要转成Integer类型。代码编写很容易出问题

        ArrayList<Object> objects = new ArrayList();
        objects.add("hello world");
        objects.add(new Integer(1));

        // 需要强转
        Object o = objects.get(0);
        //此处运行报错
        Integer index0 = (Integer)objects.get(0);
    

2.存储元素不能在编译时,提示错误,直到运行时才能抛出错误
为了解决以上问题,java1.5之后就提出了泛型的概念、泛型是一种标记在类,或者方法上的类型,他并不代表真实的类型,代表着一种行为约束

泛型的作用

        ArrayList<CharSequence> charSequences = new ArrayList<CharSequence>();
        charSequences.add("hello world");
        //编译报错
        charSequences.add(1.2);
        CharSequence charSequence = charSequences.get(0);

1.上面示例代码可以看出、在编译时,如果类型不是泛型类型,直接编译不通过
2.取出元素、不需要强制转换
3. 可以让代码抽象程度更高

java中的泛型为何要在编译后做泛型擦出

1、java1.5之后的版本,需要兼容之前没有泛型的版本、编译之后和1.5之前编译之后的字节码保持一致

        ArrayList<CharSequence> charSequences = new ArrayList<CharSequence>();
        ArrayList<String> charSequences = new ArrayList<String>();

编译后字节码一致
2、擦出之后如何避免强制转换的
如下是list get方法的源码、直接强制转换成泛型类型在这里插入图片描述

泛型的上界 和下界、对泛型做约束

java 中 使用的 super ,extends
kotlin 中使用 :
如果需要约定多个类型kotlin 可以使用where 关键字

// 泛型 上界约束
open  class Fruit(val weight: Double)
class Apple(weight: Double) : Fruit(weight)
class Banana(weight: Double) : Fruit(weight)

open interface Animal{
   
   }
class Fish( weight: Double):Animal
class Cat( weight: Double):Animal


class Monkey(weight: Double): Fruit(weight),Animal

// 容器约定必须为fruit 子类
class Container<T:Fruit>(t:T)

//只能继承一个类,实现多个接口
class  Box<T> (t:T) where T:Fruit , T:Animal

在这里插入图片描述

什么是不变

泛型不变,就类、或者方法泛型、泛型的类型 定义,不可以使用其子类或者父类来接受、java中的集合都是泛型不变的,例如 CharSequence 是String 类型的父类

  ArrayList<CharSequence> charSequences = new ArrayList<CharSequence>();
  // 不允许
 // ArrayList<CharSequence> charSequences2 = new ArrayList<String>();

什么是协变

java 中典型的例子就是数组、Fruit 是Apple 的父类、子类的类型可以用父类的类型接受
// 协变 A是B 的父类 ,那么 泛型就是泛型的父类

     // 允许
 Fruit[] arr =  new Apple[10];

在koltin 中、我们可以使用 out 关键字,打破集合的不变,实现集合的协变
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值