Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在Java中数组中删除泛型?_Java_Arrays_Generics - Fatal编程技术网

为什么在Java中数组中删除泛型?

为什么在Java中数组中删除泛型?,java,arrays,generics,Java,Arrays,Generics,我知道在Java中,泛型类型信息在编译时会被擦除,因此无法创建泛型类型的数组(因为在运行时无法有效地强制执行插入数组中的类型)。 但为什么不破例呢?为什么不保留数组的泛型类型信息(并且只保留它们的泛型类型信息)? 这背后的设计决定是什么?在我看来,这将使生活更容易,这是可能的 T[] genericArray = new T[10]; 类似于newt[10]的构造问题是指T可以是任何东西,包括Void(它实际上是一个不可实例化的类,会生成编译错误) 仔细想想,类型是一种语言构造,因此应该在编

我知道在Java中,泛型类型信息在编译时会被擦除,因此无法创建泛型类型的数组(因为在运行时无法有效地强制执行插入数组中的类型)。

但为什么不破例呢?为什么不保留数组的泛型类型信息(并且只保留它们的泛型类型信息)?

这背后的设计决定是什么?在我看来,这将使生活更容易,这是可能的

T[] genericArray = new T[10];

类似于
newt[10]的构造问题
是指
T
可以是任何东西,包括
Void
(它实际上是一个不可实例化的类,会生成编译错误)

仔细想想,类型是一种语言构造,因此应该在编译时而不是在运行时发挥作用。在某些情况下,拥有运行时类型信息是有意义的,并且某些语言实际实现了它,但是您是否需要它以及它是否是一件“好事”还存在争议™".


有关类型擦除的一些有用信息:

简短回答:

这是因为泛型是帮助编译器捕获类型的元数据 错误,所有内容都被编译为使用最小公分母 (通常是
对象
)和类型转换。这不适用于数组,因为数组 是它们自己的类。即
ArrayList
ArrayList
两者都有class
ArrayList
,但是
String
数组有class
String[]
Number
具有类
Number[]

长答案:

编译时,所有使用泛型的东西都将使用最少的 公共分母(通常是
对象
)。这可以通过 以下代码:

public class Generics {

    public static <T> void print(T what) {
        System.out.println(what);
    }

    public static <T extends Number> void printNumber(T what) {
        System.out.println(what);
    }

    public static void main(String[] args) {
        Arrays.stream(Generics.class.getDeclaredMethods())
                .filter(m -> m.getName().startsWith("print"))
                .forEach(Generics::print);
    }

}
public static void doThingsWithList() {
    ArrayList<String> list = new ArrayList<>();
    list.add("");
    String s = list.get(0);
    print(s);
}
所以我们可以看到,当它被编译时,它被编译为分别作用于
对象
数字
的方法

这就是像这样的东西将编译并运行的原因:

ArrayList<String> list = new ArrayList<>();
list.add("foo");
ArrayList<Object> list2 = (ArrayList<Object>)(Object)list;
list2.add(Integer.valueOf(10));
System.out.println(list2.get(0));
System.out.println(list2.get(1));
因此,通过向下/向上转换,我们将
ArrayList
转换为
ArrayList
——如果ArrayList实际将其内容存储在
String[]
类型的数组中,而不是
Object[]
,这是不可能的

请注意,尝试

System.out.println(list.get(0));
System.out.println(list.get(1));
将导致一个
ClassCastException
。这将提示 编译器会

请看以下代码:

public class Generics {

    public static <T> void print(T what) {
        System.out.println(what);
    }

    public static <T extends Number> void printNumber(T what) {
        System.out.println(what);
    }

    public static void main(String[] args) {
        Arrays.stream(Generics.class.getDeclaredMethods())
                .filter(m -> m.getName().startsWith("print"))
                .forEach(Generics::print);
    }

}
public static void doThingsWithList() {
    ArrayList<String> list = new ArrayList<>();
    list.add("");
    String s = list.get(0);
    print(s);
}
进入

将为false,因为第一个数组将具有class
Object[]
,第二个数组将具有class
String[]


当然,可以更改Java,使所有数组的类型都是
Object[]
所有访问都将使用强制类型转换,就像使用泛型一样。但这会破坏向后兼容性,而使用泛型则不会,因为
ArrayList
可能与
ArrayList

具有相同的类向后兼容性?这可能是重复的。@BendeguzNagy我不确定您会有什么优势在数组中使用
T[]genericArray=new T[10];
vs使用
Object[]genericArray=new Object[10]
。类型参数几乎毫无用处(除非您希望在向
T[]添加元素后genericArray
,编译器应该推断类型,不允许您添加与插入的第一个元素类型不同的元素?当然,这不可能,而且要求太高)即使在运行时,
Void
数组也没有问题。它只是另一种类型:
Void[]a=new Void[1]
该类型具有单个成员
null
。当我说不可实例化时,我指的是不能实例化
Void
对象(
new Void()
而不是
new Void[]
,实际上可以接受
Void
的数组)但是,我在回答中澄清了这个概念,并且错误地指出它生成了一个运行时错误,实际上它生成了一个编译时错误(
构造函数不可见
)。
public static void doThingsWithList();
  Code:
     0: new           #11                 // class java/util/ArrayList
     3: dup
     4: invokespecial #12                 // Method java/util/ArrayList."<init>":()V
     7: astore_0
     8: aload_0
     9: ldc           #13                 // String
    11: invokevirtual #14                 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
    14: pop
    15: aload_0
    16: iconst_0
    17: invokevirtual #15                 // Method java/util/ArrayList.get:(I)Ljava/lang/Object;
    20: checkcast     #16                 // class java/lang/String
    23: astore_1
    24: aload_1
    25: invokestatic  #17                 // Method print:(Ljava/lang/Object;)V
    28: return
public <T> T[] addToNewArrayAndPrint(T item) {
    T[] array = new T[10];
    array[0] = item;
    System.out.println(array[0]);
    return array;
}
public <T> T[] addToNewArrayAndPrint(T item) {
    Object[] array = new Object[1];
    array[0] = item;
    System.out.println((T) array[0]);
    return array;
}
Arrays.equals(addToNewArray("foo"), new String[]{ "foo" });