[改善Java代码]不能初始化泛型参数和数组
泛型类型在编译期被擦除,我们在类初始化时将无法获得泛型的具体参数,比如这样的代码:
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代码]不能初始化泛型参数和数组的更多相关文章
- [改善Java代码]强制声明泛型的实际类型
Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. import java.util.Ar ...
- [改善Java代码]动态加载不适合数组
上一个建议解释了为什么要使用forName,本建议就说说哪些地方不适合使用动态加载. 如果forName要加载一个类,那它必须是一个类------8中基本类型就排除在外.它们不是一个具体的类. 其次它 ...
- [改善Java代码]Java的泛型是类型擦除的
泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generi ...
- [改善Java代码]警惕泛型是不能协变和逆变的
什么叫做协变(covariance)和逆变(contravariance)? 在变成语言的类型框架中,协变和逆变是指宽类型和窄类型在某种情况下(如参数,泛型,返回值)替换或交换的特性,简单的说,协变是 ...
- [改善Java代码]避免带有变长参数的方法重载
建议4: 避免带有变长参数的方法重载 在项目和系统的开发中,为了提高方法的灵活度和可复用性,我们经常要传递不确定数量的参数到方法中,在Java 5之前常用的设计技巧就是把形参定义成Collection ...
- [改善Java代码]避开基本类型数组转换列表陷阱
开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import ...
- [改善Java代码]严格限定泛型类型采用多重界限
从哲学上来说,很难描述一个具体的人,你可以描述它的长相,性格,工作等,但是人都是有多重身份的,估计只有使用多个And(与操作)将所有的描述串联起来才能描述一个完整的人,人在不同的环境中角色也在不断的更 ...
- java代码的初始化过程研究
刚刚在ITeye上看到一篇关于java代码初始化的文章,看到代码我试着推理了下结果,虽然是大学时代学的知识了,没想到还能做对.(看来自己大学时掌握的基础还算不错,(*^__^*) 嘻嘻……)但 ...
- [改善Java代码]asList方法产生的List对象不可更改
上一个建议之处了asList方法在转换基本类型数组时候存在的问题,在看下asList方法返回的列表有何特殊的地方.看代码: import java.util.Arrays; import java.u ...
随机推荐
- C++问题-Qt Visual Studio Add-in
问题现象:用VS打开其他人的项目提示如下:Qt Visual Studio Add-in...中间全TMD的英文,我就省略...QT版本不对,需要修改QT版本. 问题原因:占时不明,因为我是开发Del ...
- JSF 2 checkboxes example
In JSF, <h:selectBooleanCheckbox /> tag is used to render a single HTML input element of " ...
- Spring入门(3)-Spring命名空间与Bean作用域
Spring入门(3)-Spring命名空间与Bean作用域 这篇文章主要介绍Spring的命名空间和Bean作用域 0. 目录 Spring命名空间 Bean作用域 1. Spring命名空间 在前 ...
- inline(内联函数)
一般来说,调用函数会造成:目前的指令位置被存储下来,程序流跳转到所调用的函数,然后执行调用函数,最后跳转回之前存储的位置.对于需要常常调用的小函数来说,这会影响程序的运行效率.所以,c99新增了inl ...
- Codeforces Round #271 (Div. 2) D. Flowers (递推)
题目链接:http://codeforces.com/problemset/problem/474/D 用RW组成字符串,要求w的个数要k个连续出现,R任意,问字符串长度为[a, b]时,字符串的种类 ...
- CSS构造超链接
超链接边框 派生超链接 属性选择器超链接 动态超链接 图像翻转超链接 CSS工具提示 1.给链接加上边框 A:link { Color: #f00; Text- ...
- flex 弹性合模型
网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂直居中 ...
- c++出错记录
错误1如下: vector<vector<int>> m_vc; error: '&' cannot appear in a constant-expression ...
- #定位系统性能瓶颈# strace & ltrace
strace和ltrace分别相应的是系统调用和库函数调用, 系统调用实际上就是指最底层的一个调用,在linux程序设计里面就是底层调用的意思,面向的是硬件. 而库函数调用则面向的是应用开发的.相当于 ...
- Android学习笔记(3)
今天我试着往应用里添加广告,结果adView一操作就闪退,换了很多种方法都不行. 最后解决过程有点坑爹,原来是还没setcontentview就开始adview了,哈哈 虽然我现在菜得不行,还没入门. ...