Java泛型擦除

泛型

Java泛型(generics)是JDK 5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许程序员在编译时监测非法的类型。使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类尤其有用,例如,ArrayList就是一个无处不在的集合类。

没有泛型前,集合类存放和取出都是Object,需要手动的进行强制类型转换。
一旦类型不匹配,转换将会报错。

实际的应用中,开发者往往会将同一类型的对象存放在集合中,没有泛型不仅对存放的对象没有约束,而且取出来还要进行类型转换,十分的不友好。

JDK5中引入了泛型的概念,泛型的本质是参数化类型,使得开发者可以利用集合更加方便的管理一群对象。

伪泛型

需要注意的是,Java中的泛型就是“伪泛型”。
Java只会在编译时对泛型进行校验,在运行时是没有“泛型”一说的

通过ArrayList类来看看为什么Java是“伪泛型”,以及如何实现“泛型擦除”。

ArrayList

ArrayList集合应该是开发中用的最多的集合类了。

通常我们这么用:

ArrayList<String> names = new ArrayList<>();
names.add("admin");
names.add("root");

构建一个集合,用于存放姓名,姓名都是字符串类型的,所以使用String泛型。

使用泛型后,的确我们只能add一个字符串类型,否则编译器就会报错。
看起来近乎完美,那为什么说Java的“伪泛型”呢?

我们看一下ArrayList的源码。

add()
public boolean add(E e) {
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}

调用add()时,ArrayList将对象存放到了内部的elementData[]数组中。

elementData
transient Object[] elementData;

通过查看elementData我们发现,它是个 Object[] ,而非String[],这意味着它可以存放任意类型的对象。

Java只会在编译期间帮我们校验泛型,运行时没有“泛型”一说。

ArrayList<String>底层依然使用Object[]来存放对象,当我们从names中获取元素时,Java会帮我们把Object自动的转换为String,只是转换的工作不用程序员自己去做,所以说Java的泛型是“伪泛型”。

泛型擦除

既然底层是Object[],就意味着我们可以往names中存放任意类型的对象。

涉及的知识点:反射

直接上代码:

public static void main(String[] args) throws Exception {
		ArrayList<String> names = new ArrayList<>();
		names.add("admin");
		names.add("root");
		Method add = names.getClass().getMethod("add", Object.class);
		add.invoke(names, 10);
		add.invoke(names, 19.98);
		add.invoke(names, Boolean.FALSE);
		for (Object s : names) {
			System.out.println(s.getClass().getSimpleName() + "\t:" + s);
		}
	}
输出如下:
String	:admin
String	:root
Integer	:10
Double	:19.98
Boolean	:false

我们往一个String集合中,存放了String、Integer、Double以及Boolean类型。

尾巴

MyBatis中的泛型安全问题!!!

泛型的引入,使得程序员可以更加方便的使用集合管理对象,不得不说它是一个好的设计。
但由于是“伪泛型”,所以使用时还是需要注意,否则很有可能会报错:ClassCastException。

例如:使用MyBatis框架时,我们可能希望数据库返回给我们一个int集合,
我们一般会这么写:

List<Integer> getCount();

但是MyBatis将Sql的count()函数返回值使用Long类型存放,这个方法运行不会有什么问题,因为List<Integer>是可以存放Long的,但是一旦将其取出来,转换为Integer就会报错:ClassCastException

因为Long无法转换为Integer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小潘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值