为什么我不能在Java中创建一个类型参数数组?

时间:2021-05-24 20:42:45

Well, I have read a lot of answers to this question, but I have a more specific one. Take the following snippet of code as an example.

好吧,我已经阅读了很多这个问题的答案,但我有一个更具体的问题。以下面的代码片段为例。

public class GenericArray<E>{
    E[] s= new E[5];
}

After type erasure, it becomes

在类型擦除之后,它变成了

public class GenericArray{
    Object[] s= new Object[5];
}

This snippet of code seems to work well. Why does it cause a compile-time error?

这段代码似乎运作良好。为什么会导致编译时错误?

In addition, I have known from other answers that the following codes work well for the same purpose.

此外,我从其他答案中了解到,以下代码可以很好地用于同一目的。

public class GenericArray<E>{
    E[] s= (E[])new Object[5];
}

I've read some comments saying that the piece of code above is unsafe, but why is it unsafe? Could anyone provide me with a specific example where the above piece of code causes an error?

我读过一些评论说上面的代码是不安全的,但为什么它不安全?任何人都可以提供一个特定的例子,上面的代码导致错误?

In addition, the following code is wrong as well. But why? It seems to work well after erasure, too.

另外,以下代码也是错误的。但为什么?擦除后似乎也能很好地工作。

public class GenericArray<E>{
        E s= new E();
    }

4 个解决方案

#1


3  

This snippet of code seems to work well. Why does it cause a compile-time error?

这段代码似乎运作良好。为什么会导致编译时错误?

First, because it would violate type safety (i.e. it is unsafe - see below), and in general code that can be statically determined to do this is not allowed to compile.

首先,因为它会违反类型安全性(即它不安全 - 见下文),并且通常可以静态确定执行此操作的代码不允许编译。

Remember that, due to type erasure, the type E is not known at run-time. The expression new E[10] could at best create an array of the erased type, in this case Object, rendering your original statement:

请记住,由于类型擦除,在运行时不知道类型E.表达式new E [10]最多可以创建一个擦除类型的数组,在本例中为Object,呈现原始语句:

E[] s= new E[5];

Equivalent to:

相当于:

E[] s= new Object[5];    

Which is certainly not legal. For instance:

这当然不合法。例如:

String[] s = new Object[10];

... is not compilable, for basically the same reason.

...由于基本相同的原因,不可编译。

You argued that after erasure, the statement would be legal, implying that you think this means that the original statement should also be considered legal. However this is not right, as can be shown with another simple example:

您认为在删除后,该陈述是合法的,暗示您认为这意味着原始陈述也应被视为合法。然而,这是不对的,正如另一个简单的例子所示:

ArrayList<String> l = new ArrayList<Object>();

The erasure of the above would be ArrayList l = new ArrayList();, which is legal, while the original is clearly not.

上面的擦除将是ArrayList l = new ArrayList();这是合法的,而原来显然不是。

Coming at it from a more philosophical angle, type erasure is not supposed to change the semantics of the code, but it would do so in this case - the array created would be an array of Object rather than an array of E (whatever E might be). Storing a non-E object reference in it would then be possible, whereas if the array were really an E[], it should instead generate an ArrayStoreException.

从更哲学的角度来看,类型擦除不应该​​改变代码的语义,但它会在这种情况下这样做 - 创建的数组将是一个Object数组而不是一个E数组(无论E可能是)。然后可以在其中存储非E对象引用,而如果数组实际上是E [],则应该生成ArrayStoreException。

why is it unsafe?

为什么不安全?

(Bearing in mind we are now talking about the case where E[] s= new E[5]; has been replaced with E[] s = (E[]) new Object[5];)

(请记住,我们现在讨论的情况是E [] s = new E [5];已被E [] s =(E [])替换为新对象[5];)

It is unsafe (which in this instance is short for type unsafe) because it creates at run-time a situation in which a variable (s) holds a reference to an object instance which is not a sub-type of the variable's declared type (Object[] is not a subtype of E[], unless E==Object).

它是不安全的(在这种情况下是类型unsafe的简称),因为它在运行时创建一个变量(s)保存对象实例的引用的情况,该对象实例不是变量声明类型的子类型( Object []不是E []的子类型,除非E == Object)。

Could anyone provide me with a specific example where the above piece of code causes an error?

任何人都可以提供一个特定的例子,上面的代码导致错误?

The essential problem is that it is possible to put non-E objects into an array that you create by performing a cast (as in (E[]) new Object[5]). For example, say there is a method foo which takes an Object[] parameter, defined as:

基本问题是可以将非E对象放入通过执行转换创建的数组中(如(E [])new Object [5])。例如,假设有一个方法foo,它接受一个Object []参数,定义如下:

void foo(Object [] oa) {
    oa[0] = new Object();
}

Then take the following code:

然后使用以下代码:

String [] sa = new String[5];
foo(sa);
String s = sa[0]; // If this line was reached, s would
                  // definitely refer to a String (though
                  // with the given definition of foo, this
                  // line won't be reached...)

The array definitely contains String objects even after the call to foo. On the other hand:

即使在调用foo之后,该数组肯定包含String对象。另一方面:

E[] ea = (E[]) new Object[5];
foo(ea);
E e = ea[0];  // e may now refer to a non-E object!

The foo method might have inserted a non-E object into the array. So even though the third line looks safe, the first (unsafe) line has violated the constraints that guarantee that safety.

foo方法可能已将非E对象插入到数组中。因此,即使第三条线看起来很安全,第一条(不安全)线也违反了保证安全的限制。

A full example:

一个完整的例子:

class Foo<E>
{
    void foo(Object [] oa) {
        oa[0] = new Object();
    }

    public E get() {
        E[] ea = (E[]) new Object[5];
        foo(ea);
        return ea[0];  // returns the wrong type
    }
}

class Other
{
    public void callMe() {
        Foo<String> f = new Foo<>();
        String s = f.get();   // ClassCastException on *this* line
    }
}

The code generates a ClassCastException when run, and it is not safe. Code without unsafe operations such as casts, on the other hand, cannot produce this type of error.

代码在运行时会生成ClassCastException,并且不安全。另一方面,没有诸如强制转换之类的不安全操作的代码不能产生这种类型的错误。

In addition, the following code is wrong as well. But why? It seems to work well after erasure, too.

另外,以下代码也是错误的。但为什么?擦除后似乎也能很好地工作。

The code in question:

有问题的代码:

public class GenericArray<E>{
    E s= new E();
}

After erasure, this would be:

擦除后,这将是:

Object s = new Object();

While this line itself would be fine, to treat the lines as being the same would introduce the semantic change and safety issue that I have described above, which is why the compiler won't accept it. As an example of why it could cause a problem:

虽然这条线本身很好,但将线条视为相同会引入我上面描述的语义变化和安全问题,这就是编译器不接受它的原因。作为它可能导致问题的原因的一个例子:

public <E> E getAnE() {
    return new E();
}

... because after type erasure, 'new E()' would become 'new Object()' and returning a non-E object from the method clearly violates its type constraints (it is supposed to return an E) and is therefore unsafe. If the above method were to compile, and you called it with:

...因为在类型擦除之后,'new E()'将成为'new Object()'并且从该方法返回非E对象明显违反其类型约束(它应该返回E)因此是不安全的。如果上面的方法是编译的,你用它调用它:

String s = <String>getAnE();

... then you would get a type error at runtime, since you would be attempting to assign an Object to a String variable.

...然后你会在运行时得到一个类型错误,因为你试图将一个Object分配给一个String变量。

Further notes / clarification:

进一步说明/澄清:

  • Unsafe (which is short for "type unsafe") means that it could potentially cause a run-time type error in code that would otherwise be sound. (It actually means more than this, but this definition is enough for purposes of this answer).
  • 不安全(这是“类型不安全”的缩写)意味着它可能会导致代码中的运行时类型错误,否则将是合理的。 (它实际上意味着更多,但这个定义足以满足这个答案的目的)。
  • it's possible to cause a ClassCastException or ArrayStoreException or other exceptions with "safe" code, but these exceptions only occur at well defined points. That is, you can normally only get a ClassCastException when you perform a cast, an operation that inherently carries this risk. Similarly, you can only get an ArrayStoreException when you store a value into an array.
  • 使用“安全”代码可能会导致ClassCastException或ArrayStoreException或其他异常,但这些异常仅发生在明确定义的点上。也就是说,通常只有在执行强制转换时才会获得ClassCastException,这种操作本身就存在这种风险。同样,在将值存储到数组中时,只能获得ArrayStoreException。
  • the compiler doesn't verify that such an error will actually occur before it complains that an operation is unsafe. It just knows that that certain operations are potentially able to cause problems, and warns about these cases.
  • 在抱怨操作不安全之前,编译器不会验证是否会发生此类错误。它只知道某些操作可能会导致问题,并警告这些情况。
  • that you can't create a new instance of (or an array of) a type parameter is both a language feature designed to preserve safety and probably also to reflect the implementation restrictions posed by the use of type erasure. That is, new E() might be expected to produce an instance of the actual type parameter, when in fact it could only produce an instance of the erased type. To allow it to compile would be unsafe and potentially confusing. In general you can use E in place of an actual type with no ill effect, but that is not the case for instantiation.
  • 您无法创建类型参数的新实例(或数组)既是一种旨在保护安全性的语言功能,也可能是为了反映使用类型擦除所带来的实现限制。也就是说,可能期望新的E()生成实际类型参数的实例,而实际上它只能生成擦除类型的实例。允许它编译将是不安全的并且可能令人困惑。通常,您可以使用E代替实际类型而不会产生不良影响,但实例化不是这种情况。

#2


7  

Array declarations are required to have a reifiable type, and generics are not reifiable.

数组声明需要具有可重新类型,并且泛型不可恢复。

From the documentation: the only type you can place on an array is one that is reifiable, that is:

从文档中:您可以在数组上放置的唯一类型是可以重新生成的类型,即:

  • It refers to a non-generic class or interface type declaration.

    它引用非泛型类或接口类型声明。

  • It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).

    它是一种参数化类型,其中所有类型参数都是*通配符(第4.5.1节)。

  • It is a raw type (§4.8).

    它是原始类型(§4.8)。

  • It is a primitive type (§4.2).

    它是一种原始类型(§4.2)。

  • It is an array type (§10.1) whose element type is reifiable.

    它是一种数组类型(第10.1节),其元素类型是可恢复的。

  • It is a nested type where, for each type T separated by a ".", T itself is reifiable.

    它是一种嵌套类型,其中,对于由“。”分隔的每个类型T,T本身是可恢复的。

This means that the only legal declaration for a "generic" array would be something like List<?>[] elements = new ArrayList[10];. But that's definitely not a generic array, it's an array of List of unknown type.

这意味着“通用”数组的唯一合法声明类似于List <?> [] elements = new ArrayList [10] ;.但这绝对不是通用数组,它是一个未知类型的List数组。

The main reason that Java is complaining about the you performing the cast to E[] is because it's an unchecked cast. That is, you're going from a checked type explicitly to an unchecked one; in this case, a checked generic type E to an unchecked type Object. However, this is the only way to create an array that is generic, and is generally considered safe if you have to use arrays.

Java抱怨你对E []执行强制转换的主要原因是因为它是一个未经检查的强制转换。也就是说,您将从已检查的类型明确地转到未经检查的类型;在这种情况下,检查的泛型类型E为未经检查的类型Object。但是,这是创建通用数组的唯一方法,如果必须使用数组,通常认为是安全的。

In general, the advice to avoid a scenario like that is to use generic collections where and when you can.

一般来说,避免这种情况的建议是尽可能在何时何地使用泛型集合。

#3


2  

A compiler can use a variable of type Object to do anything a variable of type Cat can do. The compiler may have to add a typecast, but such typecast will either throw an exception or yield a reference to an instance of Cat. Because of this, the generated code for a SomeCollection<T> doesn't have to actually use any variables of type T; the compiler can replace T with Object and cast things like function return values to T where necessary.

编译器可以使用Object类型的变量来执行Cat类型的变量可以执行的任何操作。编译器可能必须添加类型转换,但是这样的类型转换将抛出异常或产生对Cat实例的引用。因此,为SomeCollection 生成的代码不必实际使用任何类型为T的变量;编译器可以用Object替换T,并在必要时将函数返回值等函数转换为T.

A compiler cannot use an Object[], however, to do everything a Cat[] can do. If a SomeCollection[] had an array of type T[], it would not be able to create an instance of that array type without knowing the type of T. It could create an instance of Object[] and store references to instances of T in it without knowing the type of T, but any attempt to cast such an array to T[] would be guaranteed to fail unless T happened to be Object.

但是,编译器不能使用Object []来执行Cat []可以执行的所有操作。如果SomeCollection []有一个T []类型的数组,它将无法在不知道T类型的情况下创建该数组类型的实例。它可以创建Object []的实例并存储对T实例的引用在它不知道T的类型的情况下,但是任何将这样的数组转换为T []的尝试都将保证失败,除非T恰好是Object。

#4


0  

Let's say generic arrays are allowed in Java. Now, take a look at following code,

假设Java中允许使用通用数组。现在,看看下面的代码,

Object[] myStrs = new Object[2];
myStrs[0] = 100;  // This is fine
myStrs[1] = "hi"; // Ambiguity! Hence Error.

If user is allowed to create generic Array, then user can do as I've shown in above code and it will confuse compiler. It defeats the purpose of arrays (Arrays can handle only same/similar/homogeneous type of elements, remember?). You can always use array of class/struct if you want heterogeneous array.

如果允许用户创建通用数组,那么用户可以像我在上面的代码中所示那样做,它会混淆编译器。它违背了数组的目的(数组只能处理相同/相似/同类型的元素,还记得吗?)。如果需要异构数组,可以始终使用class / struct数组。

More info here.

更多信息在这里。

#1


3  

This snippet of code seems to work well. Why does it cause a compile-time error?

这段代码似乎运作良好。为什么会导致编译时错误?

First, because it would violate type safety (i.e. it is unsafe - see below), and in general code that can be statically determined to do this is not allowed to compile.

首先,因为它会违反类型安全性(即它不安全 - 见下文),并且通常可以静态确定执行此操作的代码不允许编译。

Remember that, due to type erasure, the type E is not known at run-time. The expression new E[10] could at best create an array of the erased type, in this case Object, rendering your original statement:

请记住,由于类型擦除,在运行时不知道类型E.表达式new E [10]最多可以创建一个擦除类型的数组,在本例中为Object,呈现原始语句:

E[] s= new E[5];

Equivalent to:

相当于:

E[] s= new Object[5];    

Which is certainly not legal. For instance:

这当然不合法。例如:

String[] s = new Object[10];

... is not compilable, for basically the same reason.

...由于基本相同的原因,不可编译。

You argued that after erasure, the statement would be legal, implying that you think this means that the original statement should also be considered legal. However this is not right, as can be shown with another simple example:

您认为在删除后,该陈述是合法的,暗示您认为这意味着原始陈述也应被视为合法。然而,这是不对的,正如另一个简单的例子所示:

ArrayList<String> l = new ArrayList<Object>();

The erasure of the above would be ArrayList l = new ArrayList();, which is legal, while the original is clearly not.

上面的擦除将是ArrayList l = new ArrayList();这是合法的,而原来显然不是。

Coming at it from a more philosophical angle, type erasure is not supposed to change the semantics of the code, but it would do so in this case - the array created would be an array of Object rather than an array of E (whatever E might be). Storing a non-E object reference in it would then be possible, whereas if the array were really an E[], it should instead generate an ArrayStoreException.

从更哲学的角度来看,类型擦除不应该​​改变代码的语义,但它会在这种情况下这样做 - 创建的数组将是一个Object数组而不是一个E数组(无论E可能是)。然后可以在其中存储非E对象引用,而如果数组实际上是E [],则应该生成ArrayStoreException。

why is it unsafe?

为什么不安全?

(Bearing in mind we are now talking about the case where E[] s= new E[5]; has been replaced with E[] s = (E[]) new Object[5];)

(请记住,我们现在讨论的情况是E [] s = new E [5];已被E [] s =(E [])替换为新对象[5];)

It is unsafe (which in this instance is short for type unsafe) because it creates at run-time a situation in which a variable (s) holds a reference to an object instance which is not a sub-type of the variable's declared type (Object[] is not a subtype of E[], unless E==Object).

它是不安全的(在这种情况下是类型unsafe的简称),因为它在运行时创建一个变量(s)保存对象实例的引用的情况,该对象实例不是变量声明类型的子类型( Object []不是E []的子类型,除非E == Object)。

Could anyone provide me with a specific example where the above piece of code causes an error?

任何人都可以提供一个特定的例子,上面的代码导致错误?

The essential problem is that it is possible to put non-E objects into an array that you create by performing a cast (as in (E[]) new Object[5]). For example, say there is a method foo which takes an Object[] parameter, defined as:

基本问题是可以将非E对象放入通过执行转换创建的数组中(如(E [])new Object [5])。例如,假设有一个方法foo,它接受一个Object []参数,定义如下:

void foo(Object [] oa) {
    oa[0] = new Object();
}

Then take the following code:

然后使用以下代码:

String [] sa = new String[5];
foo(sa);
String s = sa[0]; // If this line was reached, s would
                  // definitely refer to a String (though
                  // with the given definition of foo, this
                  // line won't be reached...)

The array definitely contains String objects even after the call to foo. On the other hand:

即使在调用foo之后,该数组肯定包含String对象。另一方面:

E[] ea = (E[]) new Object[5];
foo(ea);
E e = ea[0];  // e may now refer to a non-E object!

The foo method might have inserted a non-E object into the array. So even though the third line looks safe, the first (unsafe) line has violated the constraints that guarantee that safety.

foo方法可能已将非E对象插入到数组中。因此,即使第三条线看起来很安全,第一条(不安全)线也违反了保证安全的限制。

A full example:

一个完整的例子:

class Foo<E>
{
    void foo(Object [] oa) {
        oa[0] = new Object();
    }

    public E get() {
        E[] ea = (E[]) new Object[5];
        foo(ea);
        return ea[0];  // returns the wrong type
    }
}

class Other
{
    public void callMe() {
        Foo<String> f = new Foo<>();
        String s = f.get();   // ClassCastException on *this* line
    }
}

The code generates a ClassCastException when run, and it is not safe. Code without unsafe operations such as casts, on the other hand, cannot produce this type of error.

代码在运行时会生成ClassCastException,并且不安全。另一方面,没有诸如强制转换之类的不安全操作的代码不能产生这种类型的错误。

In addition, the following code is wrong as well. But why? It seems to work well after erasure, too.

另外,以下代码也是错误的。但为什么?擦除后似乎也能很好地工作。

The code in question:

有问题的代码:

public class GenericArray<E>{
    E s= new E();
}

After erasure, this would be:

擦除后,这将是:

Object s = new Object();

While this line itself would be fine, to treat the lines as being the same would introduce the semantic change and safety issue that I have described above, which is why the compiler won't accept it. As an example of why it could cause a problem:

虽然这条线本身很好,但将线条视为相同会引入我上面描述的语义变化和安全问题,这就是编译器不接受它的原因。作为它可能导致问题的原因的一个例子:

public <E> E getAnE() {
    return new E();
}

... because after type erasure, 'new E()' would become 'new Object()' and returning a non-E object from the method clearly violates its type constraints (it is supposed to return an E) and is therefore unsafe. If the above method were to compile, and you called it with:

...因为在类型擦除之后,'new E()'将成为'new Object()'并且从该方法返回非E对象明显违反其类型约束(它应该返回E)因此是不安全的。如果上面的方法是编译的,你用它调用它:

String s = <String>getAnE();

... then you would get a type error at runtime, since you would be attempting to assign an Object to a String variable.

...然后你会在运行时得到一个类型错误,因为你试图将一个Object分配给一个String变量。

Further notes / clarification:

进一步说明/澄清:

  • Unsafe (which is short for "type unsafe") means that it could potentially cause a run-time type error in code that would otherwise be sound. (It actually means more than this, but this definition is enough for purposes of this answer).
  • 不安全(这是“类型不安全”的缩写)意味着它可能会导致代码中的运行时类型错误,否则将是合理的。 (它实际上意味着更多,但这个定义足以满足这个答案的目的)。
  • it's possible to cause a ClassCastException or ArrayStoreException or other exceptions with "safe" code, but these exceptions only occur at well defined points. That is, you can normally only get a ClassCastException when you perform a cast, an operation that inherently carries this risk. Similarly, you can only get an ArrayStoreException when you store a value into an array.
  • 使用“安全”代码可能会导致ClassCastException或ArrayStoreException或其他异常,但这些异常仅发生在明确定义的点上。也就是说,通常只有在执行强制转换时才会获得ClassCastException,这种操作本身就存在这种风险。同样,在将值存储到数组中时,只能获得ArrayStoreException。
  • the compiler doesn't verify that such an error will actually occur before it complains that an operation is unsafe. It just knows that that certain operations are potentially able to cause problems, and warns about these cases.
  • 在抱怨操作不安全之前,编译器不会验证是否会发生此类错误。它只知道某些操作可能会导致问题,并警告这些情况。
  • that you can't create a new instance of (or an array of) a type parameter is both a language feature designed to preserve safety and probably also to reflect the implementation restrictions posed by the use of type erasure. That is, new E() might be expected to produce an instance of the actual type parameter, when in fact it could only produce an instance of the erased type. To allow it to compile would be unsafe and potentially confusing. In general you can use E in place of an actual type with no ill effect, but that is not the case for instantiation.
  • 您无法创建类型参数的新实例(或数组)既是一种旨在保护安全性的语言功能,也可能是为了反映使用类型擦除所带来的实现限制。也就是说,可能期望新的E()生成实际类型参数的实例,而实际上它只能生成擦除类型的实例。允许它编译将是不安全的并且可能令人困惑。通常,您可以使用E代替实际类型而不会产生不良影响,但实例化不是这种情况。

#2


7  

Array declarations are required to have a reifiable type, and generics are not reifiable.

数组声明需要具有可重新类型,并且泛型不可恢复。

From the documentation: the only type you can place on an array is one that is reifiable, that is:

从文档中:您可以在数组上放置的唯一类型是可以重新生成的类型,即:

  • It refers to a non-generic class or interface type declaration.

    它引用非泛型类或接口类型声明。

  • It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).

    它是一种参数化类型,其中所有类型参数都是*通配符(第4.5.1节)。

  • It is a raw type (§4.8).

    它是原始类型(§4.8)。

  • It is a primitive type (§4.2).

    它是一种原始类型(§4.2)。

  • It is an array type (§10.1) whose element type is reifiable.

    它是一种数组类型(第10.1节),其元素类型是可恢复的。

  • It is a nested type where, for each type T separated by a ".", T itself is reifiable.

    它是一种嵌套类型,其中,对于由“。”分隔的每个类型T,T本身是可恢复的。

This means that the only legal declaration for a "generic" array would be something like List<?>[] elements = new ArrayList[10];. But that's definitely not a generic array, it's an array of List of unknown type.

这意味着“通用”数组的唯一合法声明类似于List <?> [] elements = new ArrayList [10] ;.但这绝对不是通用数组,它是一个未知类型的List数组。

The main reason that Java is complaining about the you performing the cast to E[] is because it's an unchecked cast. That is, you're going from a checked type explicitly to an unchecked one; in this case, a checked generic type E to an unchecked type Object. However, this is the only way to create an array that is generic, and is generally considered safe if you have to use arrays.

Java抱怨你对E []执行强制转换的主要原因是因为它是一个未经检查的强制转换。也就是说,您将从已检查的类型明确地转到未经检查的类型;在这种情况下,检查的泛型类型E为未经检查的类型Object。但是,这是创建通用数组的唯一方法,如果必须使用数组,通常认为是安全的。

In general, the advice to avoid a scenario like that is to use generic collections where and when you can.

一般来说,避免这种情况的建议是尽可能在何时何地使用泛型集合。

#3


2  

A compiler can use a variable of type Object to do anything a variable of type Cat can do. The compiler may have to add a typecast, but such typecast will either throw an exception or yield a reference to an instance of Cat. Because of this, the generated code for a SomeCollection<T> doesn't have to actually use any variables of type T; the compiler can replace T with Object and cast things like function return values to T where necessary.

编译器可以使用Object类型的变量来执行Cat类型的变量可以执行的任何操作。编译器可能必须添加类型转换,但是这样的类型转换将抛出异常或产生对Cat实例的引用。因此,为SomeCollection 生成的代码不必实际使用任何类型为T的变量;编译器可以用Object替换T,并在必要时将函数返回值等函数转换为T.

A compiler cannot use an Object[], however, to do everything a Cat[] can do. If a SomeCollection[] had an array of type T[], it would not be able to create an instance of that array type without knowing the type of T. It could create an instance of Object[] and store references to instances of T in it without knowing the type of T, but any attempt to cast such an array to T[] would be guaranteed to fail unless T happened to be Object.

但是,编译器不能使用Object []来执行Cat []可以执行的所有操作。如果SomeCollection []有一个T []类型的数组,它将无法在不知道T类型的情况下创建该数组类型的实例。它可以创建Object []的实例并存储对T实例的引用在它不知道T的类型的情况下,但是任何将这样的数组转换为T []的尝试都将保证失败,除非T恰好是Object。

#4


0  

Let's say generic arrays are allowed in Java. Now, take a look at following code,

假设Java中允许使用通用数组。现在,看看下面的代码,

Object[] myStrs = new Object[2];
myStrs[0] = 100;  // This is fine
myStrs[1] = "hi"; // Ambiguity! Hence Error.

If user is allowed to create generic Array, then user can do as I've shown in above code and it will confuse compiler. It defeats the purpose of arrays (Arrays can handle only same/similar/homogeneous type of elements, remember?). You can always use array of class/struct if you want heterogeneous array.

如果允许用户创建通用数组,那么用户可以像我在上面的代码中所示那样做,它会混淆编译器。它违背了数组的目的(数组只能处理相同/相似/同类型的元素,还记得吗?)。如果需要异构数组,可以始终使用class / struct数组。

More info here.

更多信息在这里。