[改善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 ...
随机推荐
- DAG的生成
DAG的生成 原始的RDD(s)通过一系列转换就形成了DAG.RDD之间的依赖关系,包含了RDD由哪些Parent RDD(s)转换而来和它依赖parent RDD(s)的哪些Partitions,是 ...
- Red5源代码分析 - 关键类及其初始化过程
原文地址:http://semi-sleep.javaeye.com/blog/348768 Red5如何响应rmpt的请求,中间涉及哪些关键类? 响应请求的流程如下: 1.Red5在启动时会调用RT ...
- JSF 2.0 + Ajax hello world example
In JSF 2.0, coding Ajax is just like coding a normal HTML tag, it's extremely easy. In this tutorial ...
- thymeleaf中的th:with用法
局部变量,th:with能定义局部变量: <div th:with="firstPer=${persons[0]}"> <p> The name of th ...
- [iOS基础控件 - 6.10.6] UIApplicationDelegate & 程序启动过程
A.概念 1.移动app非常容易受到其他的系统.软件事件的干扰,如来电.锁屏 2.app受到干扰的时候,UIApplication会通知delegate,来代理处理干扰事件 3.delegate可以处 ...
- 精通Linux的“kill”命令
无论你使用哪种操作系统,你一定会遇到某个行为失常的应用,它把自己锁死并拒绝关闭.在Linux(还有Mac),你可以用一个"kill"命令强制终结它.在这个教程中,我们将展示给你多种 ...
- ASP.NET网站如何显示自己的网页图标
转载自 http://www.webtag123.com/dotnet/17238.html 1. 直接放个ico图标到你网站的根目录,并命名为favicon.ico就可以了.favicon.ico应 ...
- URAL 2065 Different Sums (找规律)
题意:构造一个数列,使得它们的区间和的种类最少,其中数列中不同的数的数目不少于k. 析:我们考虑0这个特殊的数字,然后0越多,那么总和种类最少,再就是正负交替,那么增加0的数量. 代码如下: #pra ...
- 关于cocoapods添加静态库的奇葩配置
不多说,直接上代码 当引入这个静态库时,一开始死活在编辑时找不到这个静态库. 直到看到这个贴子:http://stackoverflow.com/questions/19189463/cocoapod ...
- transition:all 0.5s linear;进度条动画效果 制作原理
Html: <span class="progress"><b ><i></i></b><em>50< ...