java 泛型问题?

public class Plate<T> {
    private T   item;
    public Plate(T t){
        item=t;
    }
    public  void set(T t){
        item=t;
    }

    public T get(){
        return item;
    }

    public static void main(String[] args) {
        Plate<String> [] arr=new Plate[10];
        //Plate<String> [] arr2=new Plate<>[10];//编译错误
        Plate<Integer> plate=new Plate<>(1);
        Object[] arr1=arr;
        arr1[0]=plate;
        String a=arr[0].get();
    }
}

请问为什么

Plate<String> [] arr=new Plate[10]

不报错,而

Plate<String> [] arr2=new Plate<>[10]

编译错误,

这两语句有什么不同?

-------------------------------后续补充--------------------------------

关于

in generics instantiation of arrays of parametrized types are illegal.

我是这样理解的,以一个例子说明一下:

static void test() { 
  Pair<Integer,Integer>[] intPairArr = new Pair<Integer,Integer>[10] ; // error 
  addElements(intPairArr);  
  Pair<Integer,Integer> pair = intPairArr[1]; 
  Integer i = pair.getFirst(); 
  pair.setSecond(i); 
} 
static void addElements( Object[] objArr) { 
  objArr[0] = new Pair<Integer,Integer>(0,0); 
  objArr[1] = new Pair<String,String>("","");      // should fail with ArrayStoreException 
}

倘若支持,则我们调用addElements方法时,将其向上转型为Object[](数组支持协变,故编译通过),则继续添加元素时,则会编译通过,这样在运行时会出现arrayStoreException,Java引入泛型其中很重要的一点就是为了安全,将运行时的异常在编译时就暴漏出来,避免出现由于数组支持协变而导致的一些异常在编译期间无法发现,可以说,不支持泛型对象数组的创建就是因为数组有协变这一特性。

而答案中所说到的关于Java不支持泛型数组很好理解,举例说明:

 T [] arr=new T[10];

这里我们假设T为String,由于Java的泛型采用擦除机制,只作用于编译时,编译之后则T都转化为Object,实际上创建的都是Object数组,则通过桥接方法转化为String时,则明显不对,故不支持泛型数组的创建。

我们可以通过迂回的方式来创建泛型数组,举例说明:

    public T[] createArray(T[] arr){
        T[] array= (T[]) new Object[arr.length];
        for (int i = 0; i <arr.length ; i++) {
            array[i]=arr[i];
        }
        return  array;
    }

实际上将传入的泛型数组copy到对应的Object数组中了。

最后一个问题,什么原因导致了Java支持数组协变这一可能出现问题的特性呢?

阅读 2.1k
3 个回答

支持数组协变是为了方便 方法重载 —— 因为 Java 刚出现的时候,Java 还没有引入泛型,如果不支持数组协变,那么对数组的某个操作,对不同类型便需要新写一个方法,就像这样:

public static void operate(String[] array) { ... }
public static void operate(Integer[] array) { ... }
public static void operate(SomeClass[] array) { ... }

而如果支持协变,那么便可以统一为:

public static void operate(Object[] array) { ... }

后来 Java5 之后 Java 引入了泛型机制,所以对数组的处理已经可以统一抽象为泛型:

public static <T> void operate(T[] array) { ... }

所以现在数组协变的地位就很尴尬了 —— 大家都嫌弃它 —— 也是个历史遗留的包袱吧。

java中的泛型被设计为不能实例化泛型数组,类型擦除了解一下。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题