022_泛型的类型檫除

一. Java泛型的实现方法: 类型擦除

1. Java的泛型是伪泛型。为什么说Java的泛型是伪泛型呢?因为, 在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。

2. Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数, 会在编译器在编译的时候去掉。这个过程就称为类型擦除。

3. 如在代码中定义的List和List等类型, 在编译后都会编程List。JVM看到的只是List, 而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方, 但是仍然无法避免在运行时刻出现类型转换异常的情况。类型擦除也是Java的泛型实现方法与C++模版机制实现方式之间的重要区别。

4. 通过例子,来证明java泛型的类型擦除

4.1. 在这个例子中,我们定义了两个LinkedList数组, 不过一个LinkedList泛型类型, 只能存储字符串。另外一个LinkedList泛型类型, 只能存储整形。最后, 我们通过list1对象和list2对象的getClass方法获取它们的类的信息, 最后发现结果为true。说明泛型类型String和Integer都被擦除掉了, 只剩下了原始类型。

public static void main(String[] args) {
	LinkedList<String> list1 = new LinkedList<String>();
	list1.add("abc");
	LinkedList<Integer> list2 = new LinkedList<Integer>();
	list2.add(123);
	System.out.println(list1.getClass() == list2.getClass());
}

5. 通过例子,来证明java泛型的类型擦除

5.1. 在程序中定义了一个LinkedList泛型类型实例化为Integer的对象, 如果直接调用add方法, 那么只能存储整形的数据。不过当我们利用反射调用add方法的时候, 却可以存储字符串、布尔、浮点数。这说明了Integer泛型实例在编译之后被擦除了, 只保留了原始类型。

public static void main(String[] args) throws Exception {
	LinkedList<Integer> list = new LinkedList<Integer>();
	list.add(123);
	list.getClass().getMethod("add", Object.class).invoke(list, "zhangsan");
	list.getClass().getMethod("add", Object.class).invoke(list, true);
	list.getClass().getMethod("add", Object.class).invoke(list, 175.3);
	for (int i = 0; i < list.size(); i++) {
		System.out.println(list.get(i));
	}
}

二. 类型擦除后保留的原始类型

1. 原始类型(raw type)就是擦除去了泛型信息, 最后在字节码中的类型变量的真正类型。无论何时定义一个泛型类型, 相应的原始类型都会被自动地提供。类型变量被擦除(crased), 并使用其限定类型(无限定的变量用Object)替换。

2. 泛型实例:

public class Pair<T> {
	private T value;
	public T getValue() {
		return value;
	}
	public void setValue(T value) {
		this.value = value;
	}
}

3. 原始类型:

public class Pair<Object> {
	private Object value;
	public Object getValue() {
		return value;
	}
	public void setValue(Object value) {
		this.value = value;
	}
}

4. 使用javap –c Pari.class 命令查看字节码文件信息:

5. 因为在Pair中, T是一个无限定的类型变量, 所以用Object替换。其结果就是一个普通的类。在程序中可以包含不同类型的Pair, 但是, 擦除类型后它们就成为原始的Pair类型了, 原始类型都是Object。

6. 如果类型变量有限定, 那么原始类型就用第一个边界的类型变量来替换。 

6.1. 比如Pair如下声明, 那么原始类型就是Comparable。

public class Pair<T extends Comparable & Serializable> { }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值