Java泛型:用参数化类型实例化数组:非法?

时间:2022-10-05 17:04:00

I must be confused here.

我一定很困惑。

I read everywhere that in generics arrays of parametrized types are illegal.

我到处都读到,在泛型数组中参数化类型是非法的。

Example from AngelikaLanger:

从AngelikaLanger示例:

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);  
} 

Quote from Langer (but everywhere else I read it says the same thing):

引用Langer的话(但是我在其他地方读到的都是一样的):

The compiler prohibits creation of arrays whose component type is a concrete parameterized type, like Pair in our example. We discussed in the preceding entry why is it reasonable that the compiler qualifies a Pair[] as illegal.

编译器禁止创建组件类型为具体参数化类型的数组,如我们示例中的Pair。我们在前面的条目中讨论了为什么编译器将一对[]限定为非法是合理的。

So far ok.

到目前为止好了。

But in my code here:

但在我的代码中:

private MyEntry<E> [] elements = (MyEntry<E>[])new Object[capacity];  

I do exactly that, it compiles fine (I use eclipse) but get a class cast exception error (Object can not be cast to MyEntry):

我确实做到了,它编译了fine(我使用eclipse),但是得到了一个类cast exception错误(对象不能被转换为MyEntry):

My question is, why does this line compiles in the first place?

我的问题是,为什么这一行首先编译?

I thought that this instantiation is disallowed by the compiler.

我认为编译器不允许这种实例化。

What I am doing wrong/differerent here?

我在这里做错什么/有什么不同?

UPDATE:

更新:

On the same page, why am I able to succesfully do:

在同一页上,为什么我能成功地做到:

List<E> elements[] = (List<E>[])new LinkedList[capacity];  

and have no runtime exceptions?

没有运行时异常吗?

UPDATE:

更新:

Everywhere I have read (mentioned Langer since she's quoted often) it says that this declaration (arrays of parametrized types) is disallowed by compiler.
I can understand what happens after that.
I can't understand why the compiler doesn't report an error.
I am not judging, I am saying everywhere I read, it says this does not compile.
Am I missreading something?

我读过的每一个地方(因为Langer经常引用她)都说编译器不允许这个声明(参数化类型的数组)。我能理解那之后会发生什么。我不明白为什么编译器不报告错误。我不是在评判,我说我读到的每一个地方,都说这不是汇编。我missreading吗?

UPDATE: I saw some comments related to the missing parameter in the new part.
This also has no issue:

更新:我看到了一些关于新部件中丢失参数的评论。这也没有问题:

List<Entry<KeyType, ValueType>> table[] = (List<Entry<KeyType, ValueType>>[])new LinkedList[capacity];

3 个解决方案

#1


2  

In your first example, there's no problem with the instantiation - here's exactly what you're creating:

在您的第一个示例中,实例化没有问题——以下就是您正在创建的:

new Object[capacity]

Perfectly legal. You do however get a runtime exception when you attempt to cast, because an array of Object is not an array of MyEntry<E>. You might have a point that the cast or declaration could be rejected by the compiler, if these generically-parameterised arrays can't exist, though this depends what order erasure kicks in. In any case, the instantiation itself is fine.

完全合法的。但是,当您尝试强制转换时,您会得到一个运行时异常,因为对象数组不是MyEntry 的数组。如果这些泛参数化的数组不存在,那么编译器可能会拒绝转换或声明,尽管这取决于擦除的顺序。无论如何,实例化本身是可以的。

In the second example, you're creating a non-generic array of LinkedList. You then assign it to a genericised reference, which at runtime will have been erased to just a List[]. This works fine (because rightly or wrongly, arrays are covariant).

在第二个示例中,您正在创建一个非通用的LinkedList数组。然后您将它分配给一个泛型引用,在运行时它将被删除为一个列表[]。这样做很好(因为无论正确与否,数组都是协变的)。

I'm not sure why you were expecting a runtime exception; it's not much different to calling, say

我不知道您为什么期望运行时异常;这和打电话没什么区别

List<E> = new LinkedList();

You would get some unchecked warnings, but nothing that would stop the code compiling or running.

您将得到一些未检查的警告,但是没有什么会阻止代码编译或运行。

#2


1  

You have completely misunderstood whatever you have read. There is absolutely nothing wrong with having the type that is an array of a parameterized type: MyEntry<E>[] or HashMap<String,Integer>[][] or whatever. You can have variables of such types all you want, and use them anywhere a type can be used.

无论你读什么,你都完全误解了。拥有参数化类型的数组类型绝对没有问题:MyEntry []或HashMap []或其他。您可以拥有这些类型的变量,并在任何地方使用它们。 ,integer>

However, with array creation, you cannot do something like new MyEntry<E>[...]. It is not allowed by the language (for type safety reasons we will not go into here), so it is a compile error.

但是,对于数组创建,您不能执行类似于new MyEntry […]的操作。该语言不允许这样做(出于类型安全的原因,我们不在这里介绍),所以这是一个编译错误。

The best solution is either new MyEntry[] (array of raw type) or new MyEntry<?>[] (array of wildcard type); either one is allowed by the language. Both of them will require you to do an explicit cast back to MyEntry<E>[].

最好的解决方案是新的MyEntry[](原始类型数组)或新的MyEntry [](通配符类型数组);任何一种语言都是允许的。这两个都需要您对MyEntry []进行显式转换。

Since you ask about your code examples, your first example is syntactically correct (there is nothing wrong with new Object[...], and it is syntactically okay to cast to MyEntry<E>[]), so there is no compile error. However, the runtime check of the cast fails at runtime, because the object's actual type Object[] is not a subtype of MyEntry[].

既然您要询问您的代码示例,那么您的第一个示例在语法上是正确的(new Object[…],从语法上来说,可以将它转换为MyEntry [],因此不会出现编译错误。但是,强制转换的运行时检查在运行时失败,因为对象的实际类型对象[]不是MyEntry[]的子类型。

The second code example is also syntactically correct, and plus the runtime check of the cast succeeds (LinkedList[] is a subtype of List[]).

第二个代码示例也是语法正确的,并且加上cast的运行时检查(LinkedList[]是List[]的子类型)。

#3


1  

Because LinkedList is an instance of List. But Object is NOT an instance of MyEntry. Also compiler don't check can one object be cast to another or not. Because it is runtime operation.

因为LinkedList是List的一个实例。但对象不是MyEntry的实例。编译器也不检查一个对象是否可以转换成另一个对象。因为它是运行时操作。

You should use:

你应该使用:

private MyEntry<E> [] elements = new MyEntry [capacity];

Or:

或者:

class SomeOtherEntry extends MyEntry {}

private MyEntry<E> [] elements = new SomeOtherEntry [capacity];

But not:

而不是:

class SomeOtherEntry extends MyEntry {}

private SomeOtherEntry <E> [] elements = new MyEntry [capacity];

UPDATE:

更新:

List<Entry<KeyType, ValueType>> [] table = (List<Entry<KeyType,ValueType>> []) new Linked[capacity];

#1


2  

In your first example, there's no problem with the instantiation - here's exactly what you're creating:

在您的第一个示例中,实例化没有问题——以下就是您正在创建的:

new Object[capacity]

Perfectly legal. You do however get a runtime exception when you attempt to cast, because an array of Object is not an array of MyEntry<E>. You might have a point that the cast or declaration could be rejected by the compiler, if these generically-parameterised arrays can't exist, though this depends what order erasure kicks in. In any case, the instantiation itself is fine.

完全合法的。但是,当您尝试强制转换时,您会得到一个运行时异常,因为对象数组不是MyEntry 的数组。如果这些泛参数化的数组不存在,那么编译器可能会拒绝转换或声明,尽管这取决于擦除的顺序。无论如何,实例化本身是可以的。

In the second example, you're creating a non-generic array of LinkedList. You then assign it to a genericised reference, which at runtime will have been erased to just a List[]. This works fine (because rightly or wrongly, arrays are covariant).

在第二个示例中,您正在创建一个非通用的LinkedList数组。然后您将它分配给一个泛型引用,在运行时它将被删除为一个列表[]。这样做很好(因为无论正确与否,数组都是协变的)。

I'm not sure why you were expecting a runtime exception; it's not much different to calling, say

我不知道您为什么期望运行时异常;这和打电话没什么区别

List<E> = new LinkedList();

You would get some unchecked warnings, but nothing that would stop the code compiling or running.

您将得到一些未检查的警告,但是没有什么会阻止代码编译或运行。

#2


1  

You have completely misunderstood whatever you have read. There is absolutely nothing wrong with having the type that is an array of a parameterized type: MyEntry<E>[] or HashMap<String,Integer>[][] or whatever. You can have variables of such types all you want, and use them anywhere a type can be used.

无论你读什么,你都完全误解了。拥有参数化类型的数组类型绝对没有问题:MyEntry []或HashMap []或其他。您可以拥有这些类型的变量,并在任何地方使用它们。 ,integer>

However, with array creation, you cannot do something like new MyEntry<E>[...]. It is not allowed by the language (for type safety reasons we will not go into here), so it is a compile error.

但是,对于数组创建,您不能执行类似于new MyEntry […]的操作。该语言不允许这样做(出于类型安全的原因,我们不在这里介绍),所以这是一个编译错误。

The best solution is either new MyEntry[] (array of raw type) or new MyEntry<?>[] (array of wildcard type); either one is allowed by the language. Both of them will require you to do an explicit cast back to MyEntry<E>[].

最好的解决方案是新的MyEntry[](原始类型数组)或新的MyEntry [](通配符类型数组);任何一种语言都是允许的。这两个都需要您对MyEntry []进行显式转换。

Since you ask about your code examples, your first example is syntactically correct (there is nothing wrong with new Object[...], and it is syntactically okay to cast to MyEntry<E>[]), so there is no compile error. However, the runtime check of the cast fails at runtime, because the object's actual type Object[] is not a subtype of MyEntry[].

既然您要询问您的代码示例,那么您的第一个示例在语法上是正确的(new Object[…],从语法上来说,可以将它转换为MyEntry [],因此不会出现编译错误。但是,强制转换的运行时检查在运行时失败,因为对象的实际类型对象[]不是MyEntry[]的子类型。

The second code example is also syntactically correct, and plus the runtime check of the cast succeeds (LinkedList[] is a subtype of List[]).

第二个代码示例也是语法正确的,并且加上cast的运行时检查(LinkedList[]是List[]的子类型)。

#3


1  

Because LinkedList is an instance of List. But Object is NOT an instance of MyEntry. Also compiler don't check can one object be cast to another or not. Because it is runtime operation.

因为LinkedList是List的一个实例。但对象不是MyEntry的实例。编译器也不检查一个对象是否可以转换成另一个对象。因为它是运行时操作。

You should use:

你应该使用:

private MyEntry<E> [] elements = new MyEntry [capacity];

Or:

或者:

class SomeOtherEntry extends MyEntry {}

private MyEntry<E> [] elements = new SomeOtherEntry [capacity];

But not:

而不是:

class SomeOtherEntry extends MyEntry {}

private SomeOtherEntry <E> [] elements = new MyEntry [capacity];

UPDATE:

更新:

List<Entry<KeyType, ValueType>> [] table = (List<Entry<KeyType,ValueType>> []) new Linked[capacity];