聊一聊Java泛型的擦除

摘要:
今天,我们主要是来聊一聊Java泛型的擦除。或许,你对Java泛型的擦除的概念不是很理解,下面我们来看一个例子:很多人会认为ArrayList和ArrayList是不同的类型,但是这段程序打印的结果是true。下面我们再来看一个例子:这种代码在Java中是不能编译通过的,即使我传的是baby这个类的对象。这种在泛型代码内部获取不到有关泛型参数类型的一种泛型实现并不是Java的语言特性,而是Java泛型实现的一种折中。Java的泛型是使用擦除实现的。

最近看了《thinking in java》的第十五章泛型,感觉有些东西需要记录下来。

泛型是Java SE5才被引入的概念,现在我的工作中泛型主要使用在集合,这样可以知道set()和get()的类型(类型检查是在编译阶段,可以使用反射绕过编译),而不必再进行额外的转型操作。

今天,我们主要是来聊一聊Java泛型的擦除。

或许,你对Java泛型的擦除的概念不是很理解,下面我们来看一个例子:

聊一聊Java泛型的擦除第1张

很多人会认为ArrayList<String>和ArrayList<Integer>是不同的类型,但是这段程序打印的结果是true。

下面我们再来看一个例子:

聊一聊Java泛型的擦除第2张

这种代码在Java中是不能编译通过的,即使我传的是baby这个类的对象。但是这种代码在C++中不仅能编译通过还能执行。

这种在泛型代码内部获取不到有关泛型参数类型的一种泛型实现并不是Java的语言特性,而是Java泛型实现的一种折中。

Java的泛型是使用擦除实现的。这也就意味着当你在使用泛型的时候,任何具体的类型信息都被擦除了,你唯一知道的是你在使用一个对象。就如同上例的ArrayList<String>和ArrayList<Integer>在运行是相同的类型,它们都被擦出成它们的原生类型,List。

如果,泛型在Java 1.0中就已经是其中一部分,那么这个特性很可能就不会有擦除来实现,将会使用具体化,使类型参数保持一致,因此就可以在类型参数上执行基于类型语言的操作和反射操作。

同样,擦除的代价也是巨大的。泛型不能用于显式的引用运行时类型的操作之中,例如转型,instanceof和new。

即使,擦除在方法体内移除了有关实际类型的信息,编译器仍能够确保在方法或者类中使用的类型的内部一致性。以为擦除在方法体内移除了类型信息,所以运行时的问题的就是边界:对象进入和离开的方法的地点。这些就是编译器在编译期执行类型检查并插入转型代码的地点。下面的例子很好的说明了这点。

聊一聊Java泛型的擦除第3张

下面是用Javap -c Test反编译这个类看到的内容

聊一聊Java泛型的擦除第4张

set()和get()方法将直接存储和产生值,转型是在调用get()的时候接受检查的。

下面我们用上泛型再看看,

聊一聊Java泛型的擦除第5张

反编译的内容如下:

聊一聊Java泛型的擦除第6张

所产生的字节码相同,对进入set()的类型检查是不需要的,因为这由编辑器执行。而对从get()返回的值仍需进行转型。

所以在泛型中的所有动作都发生在边界处。

免责声明:文章转载自《聊一聊Java泛型的擦除》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇linux应用之gcc环境的安装mysql、mongodb、redis 数据库之间的区别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Unity3D游戏轻量级xlua热修复框架

一  这是什么东西 前阵子刚刚集成xlua到项目,目的只有一个:对线上游戏C#逻辑有Bug的地方执行修复,通过考察xlua和tolua,最终选择了xlua,很大部分原因是因为项目已经到了后期,线上版本迭代了好几次,所以引入Lua的目的不是为了开发新版本模块。xlua在我们的这种情况下很是适用,如xlua作者所说,用C#开发,用lua热更,xlua这套框架为...

9本Java程序员必读的书

本文列出的9本书在Java程序员界都是被认为很棒的书。当一个程序员开始初学Java时,他的第一个问题应该是如何选择一本书来作为指导学习Java。这个问题也就表明,相对于其他的教程和博客,Java书籍还是很重要的参考,主要表现在以下两点 ●通常书籍是由比较权威的程序员来撰写的。 ●相比其他媒介,书籍对于内容的描述更加详细,解释更加明确。 本文列出的九本...

奇技淫巧:F#泛型特化的最终优化

上回讲到,F#中module里的泛型变量实际上是泛型函数。由此,在一个泛型特化的实现中出了岔子。最后通过泛型得以解决。使用 F# 来做泛型特化,相比 C# 有这个优势:F# 中直接支持函数赋值,而无须使用委托。避免了 C# 例子里面,为了节省 Lumbda 与委托之间的转换,而做出的丑陋的反射、拆箱操作。代码不再这么艰涩,我们重新来看看这段代码: modu...

java学习--基础知识进阶第六天--集合&amp;amp;迭代器、增强for &amp;amp; 泛型、常见数据结构、List子体系

今日内容介绍 u  集合&迭代器 u  增强for & 泛型 u  常见数据结构 u  List子体系 第1章 集合&迭代器 1.1 集合体系结构 1.1.1 集合体系图      在最顶层的父接口Collection中一定定义了所有子类集合的共同属性和方法,因此我们首先需要学习Collection中共性方法,然后再去针对每个子类集...

[Java] HOW2J(Java中级)

异常 定义:导致程序正常流程被中断的事件 异常处理常见手段 try catch:将可能抛出异常的代码放在try的块中,一旦出现异常就跳转到catch的块中处理 throws/throw:不在本模块处理异常,而是交给调用者处理 finally:无论是否出现异常,都会执行(保证能正常结束) 使用异常的父类进行catch:可以,但可能不精确 多异常捕捉:...

XStream xml 解析框架使用笔记

1. xml的标签可以映射为类、类成员变量 2. 有子标签的标签映射为类,没有子标签的便签映射为类成员变量 3. 类名、类成员变量名如与标签名不一致需要通过注解或代码设置别名 1 //类名 2 @XStreamAlias("Info") 3 xStream.aliasType("Info", YLTextInfo.class); 4 //类成员变量名 5...