简体   繁体   English

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

[英]Java Generics: Instantiating arrays with parameterized types: illegal?

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): 朗格的名言(但我在其他任何地方读的都说同样的话):

The compiler prohibits creation of arrays whose component type is a concrete parameterized type, like Pair in our example. 编译器禁止创建其组件类型为具体参数化类型的数组,例如本例中的Pair。 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): 我正是这样做的,它可以很好地编译(我使用eclipse),但是会收到类强制转换异常错误(对象不能强制转换为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. 我读过的所有地方(自从被频繁引用以来,都提到过Langer)都说编译器不允许此声明(参数化类型的数组)。
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? 我在念东西吗?

UPDATE: I saw some comments related to the missing parameter in the new part. 更新:我看到一些与new零件中缺少参数有关的注释。
This also has no issue: 这也没有问题:

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

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> . 但是,当您尝试进行MyEntry<E>时,确实会遇到运行时异常,因为Object数组不是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. 如果这些通用参数化的数组不存在,则可能会有一个强制转换声明会被编译器拒绝的观点,尽管这取决于擦除的顺序。无论如何,实例化本身就很好。

In the second example, you're creating a non-generic array of LinkedList . 在第二个示例中,您将创建LinkedList的非泛型数组。 You then assign it to a genericised reference, which at runtime will have been erased to just a List[] . 然后,将其分配给通用引用,该引用在运行时将被删除为List[] This works fine (because rightly or wrongly, arrays are covariant). 这很好用(因为对或错,数组是协变的)。

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. 您会得到一些未经检查的警告,但是没有什么会阻止代码的编译或运行。

Because LinkedList is an instance of List . 因为LinkedListList的实例。 But Object is NOT an instance of MyEntry . 但是Object 不是 MyEntry的实例。 Also compiler don't check can one object be cast to another or not. 同样,编译器不会检查是否可以将一个对象强制转换为另一个对象。 Because it is runtime operation. 因为它是运行时操作。

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];

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. 具有参数化类型的数组的类型绝对没有错: MyEntry<E>[]HashMap<String,Integer>[][]或其他任何东西。 You can have variables of such types all you want, and use them anywhere a type can be used. 您可以随意拥有所有此类类型的变量,并在可以使用任何类型的地方使用它们。

However, with array creation, you cannot do something like new MyEntry<E>[...] . 但是,使用数组创建时,您无法执行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. 该语言不允许这样做(出于类型安全的原因,我们将不在此处介绍),因此它是编译错误。

The best solution is either new MyEntry[] (array of raw type) or new MyEntry<?>[] (array of wildcard type); 最好的解决方案是new MyEntry[] (原始类型的数组)或new MyEntry<?>[] (通配符类型的数组); either one is allowed by the language. 语言允许任何一种。 Both of them will require you to do an explicit cast back to MyEntry<E>[] . 他们两个都需要您显式地转换回MyEntry<E>[]

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. 由于您询问的是代码示例,因此您的第一个示例在语法上是正确的( new Object[...]没错,并且在语法上也可以MyEntry<E>[]转换为MyEntry<E>[] ),因此没有编译错误。 However, the runtime check of the cast fails at runtime, because the object's actual type Object[] is not a subtype of MyEntry[] . 但是, MyEntry[]类型MyEntry[]的运行时检查在运行时失败,因为对象的实际类型Object[]不是MyEntry[]的子类型。

The second code example is also syntactically correct, and plus the runtime check of the cast succeeds ( LinkedList[] is a subtype of List[] ). 第二个代码示例在语法上也是正确的,并且强制转换的运行时检查成功( LinkedList[] List[]的子类型)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM