什么是泛型
早期在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 关键字,打破集合的不变,实现集合的协变


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

被折叠的 条评论
为什么被折叠?



