Why,Java为什么需要泛型?
如果我需要我的代码适用于多种类型,那么我可以使用object;如果我需要限定这个类型必须具有特定的约定,那么我可以定义接口或者抽象类。总之,我都可以解决,再加上Java的反射功能,没有泛型之前Collection库一样过得好好的。
那么java为什么还要加上泛型这样的语法糖呢?答案就是,在编译期间就检查类型转换是否正确,而不是拖延到运行时期。我想这也是Java泛型最吸引人的地方,它无法像C++模板那样强大,但也不是一无是处。
在泛型没有出现之前,容器里的实现都是通过超类object可以让任何对象都放进去,但是一旦放进去之后,特定类型就向上转型为object,从而丧失了类型信息。要想从里面得到特定的类型信息只有手动强制转换,但是这个转换在编译时期是无法预知的,运行时期完全有可能抛出ClassCastException异常。从软件工程的角度看,如果能在编译时期就检查类型转换十分正确,这是一种进步。
什么时候使用泛型?
如果你要编写可以应用于多种类型的代码(比如你重新定义一种数据结构,或者一种算法),你的头脑的第一反应是使用object,但是考虑前面所说的,你可以使用没有边界的泛型来代替。如果你的代码必须现定于使用某种接口或类的子类,那么可以考虑使用有边界的泛型来代替。
举例,java.lang.ThreadLocal的实现
ThreadLocal是用来为每一个线程提供一个副本,可以确保这个副本变量只在一个线程中被使用到。
典型的用法是保持数据库连接connection的线程封闭性:
private static ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};
public static Connection getConnection() {
return connectionHolder.get();
}
ThreadLocal的实现也是采用了泛型,源代码中get方法返回的是T,基于擦除的认识,在运行时,这个T实际上看不到了,也不是真正的Connection,而是普通的object,你完全可以将上面的代码<Connection>忽略掉,把ThreadLocal源代码里的T看成object,那你可能要问,它的get方法为什么就知道返回的是Connection类型呢,原因是编译器编译后,在get方法自动加上了类型转换并添加了桥方法,能做到这一步的前提是在编译时期已经经过了类型检查,如果类型检查不通过就不会生成class文件,也就不会有后面这些步骤了。
How,擦除,一种折中方案
泛型其实算不上是一种语言特性,它只是java实现泛型技术的一种折中,至于为什么选择擦除,我猜可能是为了保持向后兼容,使得泛型代码和非泛型代码能够共存。为了保持向后兼容,泛型对JVM是不可见的,也就是JVM根本不需要做很多变化,因为既然你实现泛型的主要目标是提供编译时期的类型检查安全,那么很多工作都应该在编译时期做,实际上也是这样的,擦除也就是这么一个原理,在运行时期看不见任何泛型参数,JVM执行泛型代码就像执行以前的普通代码一样!(当然不做任何改变也是不可能的,可以参考http://icyfenix.iteye.com/blog/1021949)。
我觉得理解擦除原理最重要的是区分编译时期和运行时期:
擦除步骤
首先,编译器检查类型是否安全,就像下面的代码是通不过的:
List<String > list = new ArraryList<String>();
list.add(“cantellow”);
int integer = list.get(0);//compile error
然后,将参数化类型中的类型参数"擦除"(erasure)掉,并且将类型变量用"上限(upper bound)"取代,通常情况下这些上限是 Object。这里的类型变量是指实例域,本地方法域,方法参数以及方法返回值中用来标记类型信息的"变量",例如:实例域中的变量声明 A elem;,方法声明 Node (A elem){};,其中,A 用来标记 elem 的类型,它就是类型变量。
擦除规则:
如果泛型类型的类型变量没有限定(既是<T>) ,那么我们就用Object作为原始类型;
如果有限定(<T
extends XClass>),我们就XClass作为原始类型;
如果有多个限定(<T extends XClass1&XClass2>),我们就用第一个边界的类型变量XClass1类作为原始类型;
最后,添加类型转换并插入"桥方法"(bridge method),以便覆盖(overridden)可以正常的工作。关于更详细的擦除步骤请参考:http://www.iteye.com/topic/549509
- 大小: 30.9 KB
分享到:
相关推荐
什么是泛型编程&STL,值得好好看看
主要介绍了C#泛型集合Dictionary的使用方法,本文讲解了Dictionary的多种操作方法,需要的朋友可以参考下
本篇文章主要是对C#中泛型列表List的基本用法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助
泛型类、泛型方法、泛型接口、泛型委托 泛型类、泛型方法、泛型接口、泛型委托
泛型&通配符常见面试题总结
泛型集合解释的非常好泛型集合泛型集合泛型集合解释的非常好泛型集合泛型集合泛型集合解释的非常好泛型集合泛型集合泛型集合解释的非常好泛型集合泛型集合
Struts2、Hibernate、Spring整合的泛型DAO (本人评价: 代码开发效率提高30% 代码出错率减少70%) 对于大多数开发人员,系统中的每个 DAO 编写几乎相同的代码到目前为止已经成为一种习惯。虽然所有人都将这种重复...
C#,泛型C#,泛型C#,泛型C#,泛型C#,泛型C#,泛型C#,泛型
C#的泛型C#的泛型
【Flutter】Dart 泛型 ( 泛型类 | 泛型方法 | 特定类型约束的泛型 ) https://hanshuliang.blog.csdn.net/article/details/114059611 博客源码快照
泛型学习和泛型接口和泛型经典示例
泛型和泛型集合类用法泛型和泛型集合类用法泛型和泛型集合类用法泛型和泛型集合类用法泛型和泛型集合类用法
在.NET FCL为我们提供了很多...结论:如果在C#2.0版本以上,尽量使用泛型集合类,而不使用非泛型集合类。因为,1. 泛型编程是从c#2.0开始才被.net支持的。2.泛型集合在性能和类型安全方面优于非泛型集 合。 。。。。
c#泛型类、泛型方法、泛型接口、泛型委托
C++/CLI泛型编程概览 CLI泛型介绍 CLI泛型适用对象 CLI泛型约束 CLI泛型与C++模板 讲座总结 Q&A
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...
Java泛型编程指南.pdf 此文章译自SUN的泛型编程指南
泛型的知识,请自己参考吧。主要介绍java泛型的知识。
详细的介绍了Java是伪泛型的原因,介绍了类型擦除的内容等。
Java Generics and Collections 英文版,详细描述java 泛型技术