类型擦除及通配符(由LSP原则引发的探究)

一、什么是协变与反协变

在这里插入图片描述
图中从上到下的关系就被称为协变:父类型到子类型:越来越具体specific返回值类型不变或变得更具体;异常的类型也是如此。
在这里插入图片描述
父类型à子类型:越来越具体specific。参数类型:要相反的变化,要么不变或越来越抽象

二、泛型不是协变的

在这里插入图片描述
我们观察上面 的两个说法,ArrayList 是List的子类但是List 不是 List的子类。
这是因为类型参数的类型信息在代码编译完成后被编译器丢弃;因此该类型信息在运行时不可用。
这一过程叫做类型擦除。从这里开始我们进一步对泛型和类型擦除进行了解

三、深入探究

List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
		
System.out.println(l1.getClass() == l2.getClass());


请问,上面代码最终结果输出的是什么?
上面的代码中涉及到了泛型,而输出的结果缘由是类型擦除。
类型擦除:如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。因此,生成的字节码只包含普通的类、接口和方法。
在这里插入图片描述
不能将一个整形数组视为一个数字类型的数组
在这里插入图片描述
如上图中的操作在java中是不被允许的

下图总结了泛型不是协变的结构
在这里插入图片描述
进一步探究类型擦除结果

public class Erasure <T extends String>{
//	public class Erasure <T>{
	T object;

	public Erasure(T object) {
		this.object = object;
	}
	
}

测试结果为

Field name object type:java.lang.String

由上面的代码和结果我们可以得到:
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 则会被转译成普通的 Object 类型,如果指定了上限如 则类型参数就被替换成类型上限

四、通配符

除了用 表示泛型外,还有 <?>这种形式。? 被称为通配符。
已经有了 的形式了,为什么还要引进 <?>这样的概念呢?
在现实编码中,希望泛型能够处理某一范围内的数据类型,比如某个类和它的子类,对此 Java 引入了通配符这个概念。所以,通配符的出现是为了指定泛型中的类型范围。
通配符有 3 种形式。

  1. <?>被称作无限定的通配符。
  2. <? extends T>被称作有上限的通配符。
  3. <? super T>被称作有下限的通配符。

无限定通配符 <?>
无限定通配符经常与容器类配合使用,它其中的 ? 其实代表的是未知类型,所以涉及到 ? 时的操作,一定与具体类型无关

<? extends T> <?>代表着类型未知,但是我们的确需要对于类型的描述再精确一点,我们希望在一个范围内确定类别,比如类型 A 及 类型 A 的子类都可以。
public <T> void test(Collection<T> collection){
	collection.add((T)new Integer(12));
	collection.add((T)"123");
}

public class Test2 <T,E extends T>{
	T value1;
	E value2;
}


E 类型是 T 类型的子类,显然这种情况类型参数更适合。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值