java 泛型的残酷现实就是:
在泛型代码内部,无法获得任何有关泛型参数类型的信息。
在使用泛型时,任何具体的类型都被擦除,唯一知道的是你在使用一个对象。比如:List<String>和List<Integer>在运行事实上是相同的类型。他们都被擦除成他们的原生类型,即List。
snippet 1:
package com.cognizant.ch15;
import java.lang.reflect.Array;
import java.util.Arrays;
public class ArrayMaker<T> {
private Class<T> kind;
public ArrayMaker(Class<T> kind) {
this.kind = kind;
}
@SuppressWarnings("unckecked")
T[] create(int size) {
return (T[]) Array.newInstance(kind, size);
}
public static void main(String[] args) {
ArrayMaker<String> stringMaker = new ArrayMaker<String>(String.class);
String[] stringArray = stringMaker.create(10);
System.out.println(Arrays.toString(stringArray));
}
}
ouput:[null, null, null, null, null, null, null, null, null, null]
由于擦除,kind实际上将被存储为了Class,非String.calss。在创建数组的时候,Array.newInstance()实际上并没有拥有kind所含的类型信息,因此就不会产生具体的结果。
如果要创建一个容器而不是数组,情况却有点不同:
snippet 2:
public class ListMaker<T>{
List<T> create(){
return new ArrayList<T>();
}
public static void main(String[] args){
ListMaker<String> stringMaker=new ListMaker<String>();
List<String> stringList=stringMaker.create();
}
}
擦除使得create()内部的new ArrayList<T>中的<T>被擦除了,在运行时,这个类的内部没有任何<T>,但是又不能把ArrayList<T>改为ArrayList,否则虽然编译器通过,但会给出警告。
snippet 3:
package com.cognizant.ch15;
import java.util.ArrayList;
import java.util.List;
public class FilledListMaker<T> {
List<T> create(T t, int n) {
List<T> result = new ArrayList<T>();
for (int i = 0; i < n; i++) {
result.add(t);
}
return result;
}
public static void main(String[] args) {
FilledListMaker<String> stringMaker = new FilledListMaker<String>();
List<String> list = stringMaker.create("hello", 6);
System.out.println(list);
}
}
output:[hello, hello, hello, hello, hello, hello]
编译器无法知道有关create中T的任何信息,但是他仍然可以在编译期确保放置到result中对象具有T类型。因此就有了一个现象:即使擦除在方法或类内部移除了实际类型的信息,编译器还是可以在方法或类的使用的类型的内部一致性。
那么就有一个问题:擦除后的不知道又到知道其具体类型,他是这么做到的呢?
答案是:擦除在方法体中移除了类型信息,所以在运行时的问题就是边界:即对象进入和离开方法的地点,这正是编译器在编译期执行类型检查并插入转型代码的地点。
泛型中的所有动作都发生在边界处:对传递进来的值进行额外的编译期检查,并插入 对传递出去的值的转型。
分享到:
相关推荐
Java中的泛型,在运行时刻其具体类型是被擦除的,这样我们就不能用new T(),instanceof等关操作,特别是对泛型类型的类的实例化问题,在此根据《Thinking in Java》中所讲的对类型擦除所带来问题的三种解决方案,比较...
NULL 博文链接:https://hyzhaolt.iteye.com/blog/443661
解析Java泛型的类型擦除.pdf
- 泛型擦除前的例子把这段Java代码编译成Class文件,然后再用字节码反编译后,將会发现泛型都不见了,又变回了Java泛型出现之前的写法,泛型类型都变回了原
JAVA泛型 28 类型擦除 28 实例分析 29 通配符与上下界 30 类型系统 31 开发自己的泛型类 32 最佳实践 32 参考资料 33 目录 3 JAVA注解 34 使用注解 34 开发注解 35 处理注解 35 实例分析 38 参考资料 39 JAVA反射与...
详细的介绍了Java是伪泛型的原因,介绍了类型擦除的内容等。
本文主要介绍了Java泛型的使用以及类型擦除相关的问题。具有很好的参考价值。下面跟着小编一起来看下吧
“编译器会进行泛型擦除”是一个常识了(好吧,实际擦除的是参数和自变量的类型)。这个过程由“类型擦除”实现。但是并非像许多开发者认为的那样,在 <..> 符号内的东西都被擦除了。看下面这段代码: public ...
主要介绍了详解java 中泛型中的类型擦除和桥方法的相关资料,需要的朋友可以参考下
Java 泛型最全指南(定义和使用+继承泛型类/实现泛型接口+泛型的边界+通配符+类型擦除)
2. 类型擦除:Java泛型在编译时实现类型安全检查,但在运行时会将泛型类型的信息擦除,转换为原始类型。这是为了保持与Java早期版本的兼容性,同时减少运行时的开销。例如,List在运行时会被擦除为List。 3. 上限和...
环境:Windows XP Professional、JDK 1.6、Ant 1.7 说明:Java泛型的动机是为解决类型转换在编译时不报错的问题。另外由于“范型编程”(Generic Programming)的推广,于是2004年JDK 5.0引用范型标准。本例子说明...
泛型擦除(Generic erase)(教学视频+源代码) 源代码中使用的泛型,在经过编辑后,代码中就看不到泛型,也就是所谓的泛型擦除 泛型擦除不是泛型丢失了,而是在编译后的字节码文件中使用单独的标识来存储泛型了。...
学习和理解Java泛型的基本概念和语法; 实际项目中需要使用泛型来增加类型安全性和重用性的开发任务。 目标: 本代码资源的目标是帮助读者理解泛型的用法和优势,并通过实际的示例代码加深对泛型的掌握。读者可以...
主要介绍了JAVA泛型的继承和实现、擦除原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了Java编程探索之泛型擦除实例解析,具有一定参考价值,需要的朋友可以了解下。
6.2. 擦除和翻译(Erasure and Translation) 6.3. 在老代码中使用泛型代码 7. 要点(The Fine Print) 7.1. 一个泛型类被其所有调用共享 7.2. 转型和instanceof 7.3. 数组Arrays 8. Class Literals as Run-time Type ...
泛型与集合 使用 进行初步翻译. 将利用碎片时间进行整理和校对,完整的时间段适合做其他需要大量思考的事,如果你有兴趣欢迎提交PR。 TODO 数据校对 目录 2.4 获取和放置原则 2.5 数组 2.6 通配符与类型参数 2.7 ...
泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。泛型是参数化类型的应用,操作的数据类型不限定于特定类型,可以根据实际需要设置不同的数据类型,以实现代码复用。下面小编来简单讲...
本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。 泛型基础 泛型类 我们首先定义一个简单的Box类: public class Box { private String object; ...