[改善Java代码]不能初始化泛型参数和数组
2016-06-28 17:12
393 查看
泛型类型在编译期被擦除,我们在类初始化时将无法获得泛型的具体参数,比如这样的代码:
这段代码有什么问题?
t,tArray,list都是类变量,都是通过new声明了一个类型,看起来非常的相似.
但是这段代码是通不过的,因为编译期在编译时需要获得T类型,但是泛型在编译期类型已经被擦除了,所以new T()和new T[5] 都会报错,
但是你也许会认为,泛型类型可以擦除为顶级的Object类,那T类型擦除成Object不就可以编译了?
这样也不行,泛型只是Java语言的一部分,Java语言毕竟是一种强类型,编译型的安全语言,要确保运行期的稳定性和安全性就必须要求在编译器上严格检查.
但是为什么new ArrayList<T>()却不会报错呢?
这是因为ArrayList表面上是泛型,其实已经在编译期转型为了Object类型了,要看一下ArrayList的源代码就清楚了.
注意看elementData定义,它容纳了ArrayList的所有元素,其类型是Object数组,因为Object是所有类的父类,数组又允许协变(Covariant),因此elementData数组可以容纳所有的实例对象.
元素加入时向上转型为Object类型(E类型转变为Object),取出时向下转型为E类型(Object转为E类型).
在某些情况下,我们确实需要泛型数组,怎么处理?
此时运行就没有任何问题了,剩下的问题就是怎么在运行期获得T的类型.也就是tType参数.一般情况下泛型类型是无法获取的,不过在客户端调用时多传输一个T类型的class就会解决问题.
类的成员变量是在类初始化前初始化的,所以要求在初始化前它必须具有明确的类型.否则就只能声明,不能初始化.
class Foo<T>{ //private T t =new T();//报错Cannot instantiate the type T //private T[] tArray= new T[5];//报错Cannot create a generic array of T private List<T> list= new ArrayList<T>(); }
这段代码有什么问题?
t,tArray,list都是类变量,都是通过new声明了一个类型,看起来非常的相似.
但是这段代码是通不过的,因为编译期在编译时需要获得T类型,但是泛型在编译期类型已经被擦除了,所以new T()和new T[5] 都会报错,
但是你也许会认为,泛型类型可以擦除为顶级的Object类,那T类型擦除成Object不就可以编译了?
这样也不行,泛型只是Java语言的一部分,Java语言毕竟是一种强类型,编译型的安全语言,要确保运行期的稳定性和安全性就必须要求在编译器上严格检查.
但是为什么new ArrayList<T>()却不会报错呢?
这是因为ArrayList表面上是泛型,其实已经在编译期转型为了Object类型了,要看一下ArrayList的源代码就清楚了.
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. */ private transient Object[] elementData; /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this(10); } /** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { rangeCheck(index); return elementData(index); } E elementData(int index) { return (E) elementData[index]; } }
注意看elementData定义,它容纳了ArrayList的所有元素,其类型是Object数组,因为Object是所有类的父类,数组又允许协变(Covariant),因此elementData数组可以容纳所有的实例对象.
元素加入时向上转型为Object类型(E类型转变为Object),取出时向下转型为E类型(Object转为E类型).
在某些情况下,我们确实需要泛型数组,怎么处理?
import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; public class Client { public static void main(String[] args) { } } class Foo<T>{ //不再初始化,由构造函数初始化 private T t; private T[] tArray; private List<T> list= new ArrayList<T>(); //构造函数初始化 public Foo(){ try { Class<?> tType = Class.forName(""); t = (T)tType.newInstance(); tArray = (T[])Array.newInstance(tType,5); } catch (Exception e) { e.printStackTrace(); } } }
此时运行就没有任何问题了,剩下的问题就是怎么在运行期获得T的类型.也就是tType参数.一般情况下泛型类型是无法获取的,不过在客户端调用时多传输一个T类型的class就会解决问题.
类的成员变量是在类初始化前初始化的,所以要求在初始化前它必须具有明确的类型.否则就只能声明,不能初始化.
相关文章推荐
- java mvc web 项目web.xml头改错了,死活加载不上springMvc的jar
- [Java] JSP笔记 - Filter 过滤器
- [改善Java代码]Java的泛型是类型擦除的
- 解决java compiler level does not match the version of the installed java project facet
- Java开发中的‘暗坑’
- javaweb热部署详解
- Eclipse项目转AndroidStudio遇到问题记录
- [改善Java代码]使用CyclicBarrier让多线程齐步走
- Java的位运算符详解实例
- spring mvc里的验证码
- 简单的邮件开发3---Java
- [改善Java代码]使用CountDownLatch协调子线程
- Java编程常见问题汇总
- SpringMVC 和Struts2的区别
- Java GC堆和jvm参数设置
- spring bean id和bean name的区别
- [改善Java代码]适当设置阻塞队列长度
- javax.inject中@Inject、@Named、@Qualifier和@Provider用法
- JAVA 图像处理库 Thumbnails
- 遍历Map的四种方法