[改善Java代码]Java的泛型是类型擦除的
泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型.
Java泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,它与C++中的模板templates比较类似.但是有一点,Java的反省在编译期有效,在运行期被删除,也就是说所有的泛型参数类型在编译后都会被清除掉.
看如下代码:
import java.util.List;
public class Foo {
//arrayMethod接受数组参数,并进行重载
public void arrayMethod(String[] strArray){}
public void arrayMethod(Integer[] intArray){}
//listMethod接收泛型List参数,并进行重载
public void listMethod(List<String> strList){}
public void listMethod(List<Integer> intList){}
}
编写了4个方法,arrayMethod方法接收String数组和Integer数组,这是一个典型的重载,listMethod接收元素类型为String和Integer的List变量.
但是这段代码不能通过编译,不能通过通过编译是在listMethod方法上.
提示:Erasure of method listMethod(List<String>) is the same as another method in type Foo && Erasure of method listMethod(List<Integer>) is the same as another method in type Foo
是说listMethod对应的这两个方法在编译时擦除类型后的方式是listMethod(List<E>),它与另外一个方法重复,通俗的说就是方法签名重复,这就是Java泛型擦除引起问题:在编译后所有的泛型类型都会做相应的转化.
转换规则如下:
1.List<String>,List<Integer>,List<T>泛型擦除后的类型为List.
2.List<String>[]擦除之后的类型是List[]
3.List<? extends E>,List<? super E>擦除之后对应类型是List<E>
4.List<T extends Serializable & Cloneable>擦除之后为List<Serializable>
Java编译后的字节码中已经没有泛型的任何信息了,也就说一个泛型类和一个普通类在经过编译后都指向了同一字节码,比如Foo<T>类,经过编译后将只有一份Foo.class类.
不管是Foo<String>还是Foo<Integer>引用的都是同一个字节码,Java之所以这样处理有两方面原因:
1.避免JVM大换血.C++的泛型生命期延续到了运行期,而Java是在编译器擦除掉的,如果JVM也把泛型类型延续到运行期,那么JVM就需要进行大量的重构工作了.
2.版本兼容,在 编译期擦除可以更好的支持原生类型RawType,在Java1.5或1.6平台上,即使声明一个List这样的原生类型也是可以正常编译通过的,只是会产生警告信息而已.
这样就可以解释如下问题了:
(1)泛型的class对象都是相同的.
每个类都有一个class属性,泛型化不会改变class属性的返回值.例如:
import java.util.ArrayList;
import java.util.List; public class Client {
public static void main(String[] args) {
List<String> ls = new ArrayList<String>();
List<Integer> li = new ArrayList<Integer>();
System.out.println(li.getClass() == li.getClass());
}
}
以上代码会返回true,List<String>和List<Integer>擦除后的类型都是List,没有任何的区别.
(2)泛型数组初始化时不能声明泛型的类型
原因很简单,可以声明一个带有泛型参数的数组,但是不能初始化该数组,因为执行了类型擦除操作,List<Object>[] 与List<String>就是一回事了,编译器拒绝如此的声明.
(3)instanceof不允许穿在泛型参数
原因 一样,泛型类型的被擦除了.
import java.util.ArrayList;
import java.util.List; public class Client {
public static void main(String[] args) {
//List<String>[] listArray = new List<String>[];
/*
如上语句报错
Multiple markers at this line
- Variable must provide either dimension expressions or an array initializer
- Cannot create a generic array of List<String>
*/
List<String>[] listArray2; //只声明不初始化没有问题.
//======================================分割线============ List<String> list = new ArrayList<String>();
System.out.println(list instanceof List);//没有泛型就不会报错,
//System.out.println(list instanceof List<String>);//有泛型就报错.
/*
Cannot perform instanceof check against parameterized type List<String>.
Use the form List<?> instead since further generic type information will be erased at runtime
*/ List<String> list2 = new ArrayList<String>();
List l = list2;
l.add(123);
}
}
[改善Java代码]Java的泛型是类型擦除的的更多相关文章
- Java泛型:类型擦除
类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...
- Java泛型之类型擦除
类型擦除 学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组.无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦): ...
- 泛型的类型擦除后,fastjson反序列化时如何还原?
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是Hydra~ 在前面的文章中,我们讲过Java中泛型的类型擦除,不过有小伙伴在后台留言提出了一个问题,带有泛型的实体的反序列化 ...
- [改善Java代码]强制声明泛型的实际类型
Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. import java.util.Ar ...
- [改善Java代码]不能初始化泛型参数和数组
泛型类型在编译期被擦除,我们在类初始化时将无法获得泛型的具体参数,比如这样的代码: class Foo<T>{ //private T t =new T();//报错Cannot inst ...
- Java泛型-类型擦除
一.概述 Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变 ...
- 转:有关Java泛型的类型擦除(type erasing)
转载自:拈花微笑 自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资.在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结 ...
- java之集合类框架的简要知识点:泛型的类型擦除
这里想说一下在集合框架前需要理解的小知识点,也是个人的肤浅理解,不知道理解的正不正确,请大家多多指教.这里必须谈一下java的泛型,因为它们联系紧密,我们先看一下这几行代码: Class c1 = n ...
- java 泛型的类型擦除与桥方法
泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...
随机推荐
- POJ 1258 Agri-Net (最小生成树)
Agri-Net 题目链接: http://acm.hust.edu.cn/vjudge/contest/124434#problem/H Description Farmer John has be ...
- JSF 2 checkboxes example
In JSF, <h:selectBooleanCheckbox /> tag is used to render a single HTML input element of " ...
- Linux优化之IO子系统监控与调优
Linux优化之IO子系统 作为服务器主机来讲,最大的两个IO类型 : 1.磁盘IO 2.网络IO 这是我们调整最多的两个部分所在 磁盘IO是如何实现的 在内存调优中,一直在讲到为了加速性能,linu ...
- 代码静态分析工具——splint的学习与使用
引言 最近在项目中使用了静态程序分析工具PC-Lint,体会到它在项目实施中带给开发人员的方便.PC-Lint是一款针对C/C++语言.windows平台的静态分析工具,FlexeLint是针对其他平 ...
- 连接查询中on and和on where的区别
一.区别 1. and条件是在生成临时表时使用的条件,它不管and中的条件是否为真,都会返回左(或者右)边表中的记录. 2.where条件是在临时表生成好后,再对临时表进行过滤的条件.这时已经没有le ...
- SessionFactory、HibernateTemplate、HibernateDaoSupport之间的关系说明
在接触HibernateTemplate之前,我们知道,在对数据库进行CRUD操作之前,需要开启session.transaction等等.在hibernate学习过程中,我们知道了,得到sessio ...
- php and web service with wsdl
Following are the links: Developing Web Services Using PHP PHP Web Services with WSDL Creating Web S ...
- 很近没读书了,读书笔记之<<大道至简>>
空闲时间不想虚度,不知道干啥的时候,就读读存在移动硬盘里的电子书吧,已经放了N久了,不知道什么时候放的,好像是大学刚毕业的时候下载的,...... 好久...... 现在才去读..是不是太晚了.... ...
- 在Linux(Ubuntu/openSUSE/CentOS)下配置ASP.NET(Apache + Mono)转载+补充
错误:Network error: Connection refused 解决办法: 执行 $sudo apt-get install openssh-server 安装ssh协议 执行ifconfi ...
- c# 反射学习笔记
首先了解C#反射的概念,反射是一个运行库类型发现的过程.通过反射可以得到一个给定程序集所包含的所有类型的列表, 这个列表包括给定类型中定义的方法.字段.属性和事件.也可以动态的发现一组给定类支持的借口 ...