1. Java范型时编译时技术,在运行时不包含范型信息,仅仅Class的实例中包含了类型参数的定义信息。
泛型是通过java编译器的称为擦除(erasure)的前端处理来实现的。你可以(基本上就是)把它认为是一个从源码到源码的转换,它把泛型版本转换成非泛型版本。 基本上,擦除去掉了所有的泛型类型信息。所有在尖括号之间的类型信息都被扔掉了,因此,比如说一个List<String>类型被转换为List。所有对类型变量的引用被替换成类型变量的上限(通常是Object)。而且,无论何时结果代码类型不正确,会插入一个到合适类型的转换。

   <T> T badCast(T t, Object o) {
return (T) o; // unchecked warning
}

类型参数在运行时并不存在。这意味着它们不会添加任何的时间或者空间上的负担,这很好。不幸的是,这也意味
着你不能依靠他们进行类型转换。

2.一个泛型类被其所有调用共享
下面的代码打印的结果是什么?

   List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());

或许你会说false,但是你想错了。它打印出true。因为一个泛型类的所有实例在运行时具有相同的运行时类(class),
而不管他们的实际类型参数。
事实上,泛型之所以叫泛型,就是因为它对所有其可能的类型参数,有同样的行为;同样的类可以被当作许多不同
的类型。作为一个结果,类的静态变量和方法也在所有的实例间共享。这就是为什么在静态方法或静态初始化代码
中或者在静态变量的声明和初始化时使用类型参数(类型参数是属于具体实例的)是不合法的原因。

3. 转型和instanceof
泛型类被所有其实例(instances)共享的另一个暗示是检查一个实例是不是一个特定类型的泛型类是没有意义的。

   Collection cs = new ArrayList<String>();
if (cs instanceof Collection<String>) { ...} // 非法

类似的,如下的类型转换
Collection<String> cstr = (Collection<String>) cs;
得到一个unchecked warning,因为运行时环境不会为你作这样的检查。

4. Class的范型处理
Java 5之后,Class变成范型化了。
JDK1.5中一个变化是类 java.lang.Class是泛型化的。这是把泛型扩展到容器类之外的一个很有意思的例子。

现在,Class有一个类型参数T, 你很可能会问,T 代表什么?它代表Class对象代表的类型。比如说,String.class类型代表 Class<String>,Serializable.class代表 Class<Serializable>。这可以被用来提高你的反射代码的类型安全。

特别的,因为 Class的 newInstance() 方法现在返回一个T, 你可以在使用反射创建对象时得到更精确的类型。比如说,假定你要写一个工具方法来进行一个数据库查询,给定一个SQL语句,并返回一个数据库中符合查询条件
的对象集合(collection)。

一个方法是显式的传递一个工厂对象,像下面的代码:
interface Factory<T> {

public T[] make();

}
public <T> Collection<T> select(Factory<T> factory, String statement) {

    Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( int i=0; i<10; i++ ) { /* iterate over jdbc results */
T item = factory.make();
/* use reflection and set all of item’s fields from sql results */
result.add( item );
}
return result;

}
你可以这样调用:
select(new Factory<EmpInfo>(){

 public EmpInfo make() {
return new EmpInfo();
}
} , ”selection string”);

也可以声明一个类 EmpInfoFactory 来支持接口 Factory:
class EmpInfoFactory implements Factory<EmpInfo> { ...

public EmpInfo make() { return new EmpInfo();}

}
然后调用:
select(getMyEmpInfoFactory(), "selection string");
这个解决方案的缺点是它需要下面的二者之一:
调用处那冗长的匿名工厂类,或为每个要使用的类型声明一个工厂类并传递其对象给调用的地方这很不自然。

使用class类型参数值是非常自然的,它可以被反射使用。没有泛型的代码可能是:
Collection emps = sqlUtility.select(EmpInfo.class, ”select * from emps”); ...
public static Collection select(Class c, String sqlStatement) {

 Collection result = new ArrayList();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
Object item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;

}
但是这不能给我们返回一个我们要的精确类型的集合。现在Class是泛型的,我们可以写:
Collection<EmpInfo> emps=sqlUtility.select(EmpInfo.class, ”select * from emps”); ...
public static <T> Collection<T> select(Class<T>c, String sqlStatement) {

 Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;

}
来通过一种类型安全的方式得到我们要的集合。
这项技术是一个非常有用的技巧,它已成为一个在处理注释(annotations)的新API中被广泛使用的习惯用法。

5. 为了保证代码的兼容性,下面的代码编译器(javac)允许,类型安全有你自己保证
List l = new ArrayList<String>();
List<String> l = new ArrayList();

6. 在将你的类库升级为范型版本时,慎用协变式返回值。
例如,将代码
public class Foo {

 public Foo create(){
return new Foo();
}

}

public class Bar extends Foo {

 public Foo create(){
return new Bar();
}

}
采用协变式返回值风格,将Bar修改为
public class Bar extends Foo {

 public Bar create(){
return new Bar();
}

}
要小心你类库的客户端。
上海尚学堂java培训原作,请多关注。陆续java相关技术文章奉上!

JAVA泛型实现原理的更多相关文章

  1. Java泛型-内部原理: 类型擦除以及类型擦除带来的问题

    一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...

  2. 关于Java泛型实现原理的思考与一般用法示例总结

    面向对象的一个重要目标是对代码重用的支持.支持这个目标的一个重要机制就是泛型机制.在1.5版本之前,java并没有直接支持泛型实现,泛型编程的实现时通过使用继承的一些基本概念来完成的. 这种方式的局限 ...

  3. java 泛型实现原理

    泛型思想最早在C++语言的模板(Templates)中产生,Java后来也借用了这种思想.虽然思想一致,但是他们存在着本质性的不同. C++中的模板是真正意义上的泛型,在编译时就将不同模板类型参数编译 ...

  4. java泛型学习(2)

    一:深入泛型使用.主要是父类和子类存在泛型的demo /** * 父类为泛型类 * @author 尚晓飞 * @date 2014-7-15 下午7:31:25 * * * 父类和子类的泛型. * ...

  5. Java泛型总结---基本用法,类型限定,通配符,类型擦除

    一.基本概念和用法 在Java语言处于还没有出现泛型的版本时,只能通过Object是所有类型的父类和类型强制转换两个特点的配合来实现类型泛化.例如在哈希表的存取中,JDK1.5之前使用HashMap的 ...

  6. 浅析Java泛型

    什么是泛型? 泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型.这种参数类型 ...

  7. 大白话说Java泛型(一):入门、原理、使用

    文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型(一):入门.原理.使用> 远在 JDK 1.4 版本的时候,那时候是没有泛型的概念的.当时 Java 程序员们写集合类的 ...

  8. java泛型的作用及实现原理

    一.泛型的介绍 泛型是Java 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. Ja ...

  9. 大白话说Java泛型:入门、使用、原理

    文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型:入门.使用.原理> 远在 JDK 1.4 版本的时候,那时候是没有泛型的概念的.当时 Java 程序员们写集合类的代码都 ...

随机推荐

  1. SPA

    为什么用SPA 1. 减少服务器压力  如果不用spa  那么每次切换页面的时候,就会向服务器发送一个请求 服务器返回一个html文件   如果使用了SPA  在切换时,不需要请求服务器,只要通过本地 ...

  2. LR回放https协议脚本失败:[GENERAL_MSG_CAT_SSL_ERROR]connect to host "XXX" failed:[10054] Connection reset by peer [MsgId:MERR-27780]

    Loadrunner默认发送是通过sockets(将http转换为sockets)发送的,而sockets默认SSL的版本为SSL2和SSL3.HTTPS协议录制的脚本以SSL3版本回放时会使sock ...

  3. 面试简单整理之rabbitmq

    135.rabbitmq 的使用场景有哪些? 单反单收,单发多收,发布订阅,按路由发送,按主题发送 136.rabbitmq 有哪些重要的角色? Server,Consumer,Producer 13 ...

  4. 如何将一个excel表格的数据匹配到另一个表中

    我们在操作excel表的时,有时需要将一个excel表中的数据匹配到另一个表中,那么就需要用到VLOOKUP函数,VLOOKUP函数是Excel中的一个纵向查找函数,VLOOKUP是按列查找,最终返回 ...

  5. HTML5-之workers(多线程执行)

    注:test.js 不涉及DOM元素

  6. DWR使用总结

      这两天学了下DWR,现在总结一下. DWR是方便使用AJAX连接JS和JAVA的的一个框架,把服务器端 Java 对象的方法公开给 JavaScript 代码. 如果是用dwr2.0的jar包,还 ...

  7. javascript和c#aes加密方法互解

    关键信息如下. javascript function Encrypt() { var key = CryptoJS.enc.Utf8.parse('8080808080808080'); var i ...

  8. Maven学习 八 采用Maven搭建SSM环境

    第一步:创建一个Maven项目 项目的打包方式选择,war 第二步:在webapp下面创建java web项目的目录结构,并配置web.xml文件 <?xml version="1.0 ...

  9. 异常:No Spring WebApplicationInitializer types detected on classpath

    原因: 启动服务提供者/服务消费者-->去注册中心Zookeeper无法注册这个服务 / 在监控中心无法发现服务 异常提示:No Spring WebApplicationInitializer ...

  10. easy-ui treegrid 实现分页 并且添加自定义checkbox

    首先第一点easy-ui  treegrid 对分页没有好的实现, 因为在分页的过程中是按照 根节点来分页的  后台只能先按照 根节点做分页查询  再将子节点关联进去, 这样才能将treegrid 按 ...