zoukankan      html  css  js  c++  java
  • [改善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的源代码就清楚了.

     1 public class ArrayList<E> extends AbstractList<E>
     2         implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
     3     /**
     4      * The array buffer into which the elements of the ArrayList are stored.
     5      * The capacity of the ArrayList is the length of this array buffer.
     6      */
     7     private transient Object[] elementData;
     8     /**
     9      * Constructs an empty list with an initial capacity of ten.
    10      */
    11     public ArrayList() {
    12         this(10);
    13     }    
    14         
    15     /**
    16      * Returns the element at the specified position in this list.
    17      *
    18      * @param  index index of the element to return
    19      * @return the element at the specified position in this list
    20      * @throws IndexOutOfBoundsException {@inheritDoc}
    21      */
    22     public E get(int index) {
    23         rangeCheck(index);
    24 
    25         return elementData(index);
    26     }
    27     E elementData(int index) {
    28         return (E) elementData[index];
    29     }        
    30 }

     注意看elementData定义,它容纳了ArrayList的所有元素,其类型是Object数组,因为Object是所有类的父类,数组又允许协变(Covariant),因此elementData数组可以容纳所有的实例对象.

    元素加入时向上转型为Object类型(E类型转变为Object),取出时向下转型为E类型(Object转为E类型).

    在某些情况下,我们确实需要泛型数组,怎么处理?

     1 import java.lang.reflect.Array;
     2 import java.util.ArrayList;
     3 import java.util.List;
     4 
     5 public class Client {
     6     public static void main(String[] args) {
     7         
     8         
     9     }
    10 }
    11 
    12 class Foo<T>{
    13     //不再初始化,由构造函数初始化
    14     private T t;
    15     private T[] tArray;
    16     private List<T> list= new ArrayList<T>();
    17     //构造函数初始化
    18     public Foo(){
    19         try {
    20             Class<?> tType = Class.forName("");
    21             t = (T)tType.newInstance();
    22             tArray = (T[])Array.newInstance(tType,5);
    23         } catch (Exception e) {
    24             e.printStackTrace();
    25         }
    26     
    27     }
    28 }

    此时运行就没有任何问题了,剩下的问题就是怎么在运行期获得T的类型.也就是tType参数.一般情况下泛型类型是无法获取的,不过在客户端调用时多传输一个T类型的class就会解决问题.

    类的成员变量是在类初始化前初始化的,所以要求在初始化前它必须具有明确的类型.否则就只能声明,不能初始化.

  • 相关阅读:
    骑行318、 2016.7.22
    骑行318、 2016.7.21
    自定义的cell上面有图片时,如果产生了重用,图片可能会错乱问题
    当前View的坐标相对其他View的位置坐标
    自定义UIButton 实现图片和文字 之间距离和不同样式
    自定义导航栏 标题视图 返回按钮
    IOS 隐藏tabBar
    ShareSDK集成遇到问题
    导航栏相关设置
    根据字符内容计算宽高度
  • 原文地址:https://www.cnblogs.com/DreamDrive/p/5624165.html
Copyright © 2011-2022 走看看