为什么" java.lang.ClassCastException:[Ljava.lang.Object;无法转换为“有界类型参数而不是形式类型参数错误? [英] Why "java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to" error for Bounded type parameters and not for Formal Type parameters?
问题描述
由于Java没有通用数组,因此我经常使用将Object数组转换为类型参数的技巧.当我有一个像< T>
这样的形式类型参数时,这很好用,但是当我使用有界的类型参数< T扩展某些东西>
时,这种方法就很好.
Since java does not have a generic array, I am using the regular trick of casting Object array to a type parameter. This is working fine when I have a formal type parameter like <T>
but not when I use bounded type parameter <T extends something>
.
使用正式类型的以下代码可以正常工作
Following Code using formal type works fine
public class Deck <T> {
private T [] cards;
private int size;
public Deck () {
cards = (T []) new Object[52];
size = 0;
}
}
public class BlackJackGame {
Deck<BlackJackCard> deck;
public BlackJackGame() {
deck = new Deck<>();
populate (deck);
deck.shuffle();
}
}
public class BlackJackCard extends Card {
}
以下使用有限类型的代码引发错误
Following code using bounded type throws error
public class Deck <T extends Card> {
private T [] cards;
private int size;
public Deck () {
cards = (T []) new Object[52];
size = 0;
}
}
public class BlackJackGame {
Deck<BlackJackCard> deck;
public BlackJackGame() {
deck = new Deck<>();
populate (deck);
deck.shuffle();
}
}
public class BlackJackCard extends Card {
}
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LCard;
at Deck.<init>(Deck.java:10)
at BlackJackGame.<init>(BlackJackGame.java:5)
推荐答案
这个示例让我想起了早些时候,当我在有效的Java"一书中阅读有关泛型的信息时...
This example remind me early days, when I'm reading about Generics in "Effective java" book ...
首先,这是java泛型的黄金法则:不要将数组和泛型混合使用,因为您有很好的机会生成不安全的代码.您的代码将泛型(例如T,T扩展Card)与数组(例如T []卡)混合在一起.然后,您在运行时得到了不安全的代码.
First thing first, here is java generics golden rule : don't mix arrays and generics, because you get a good chance to produce unsafe code. Your code mixes generics (e.g. T, T extends Card) with arrays (e.g. T [] cards). Then, you got unsafe code in runtime.
这是一种安全的方法(优先选择列表而不是数组):
This is one safe way (prefer lists over arrays):
class Deck <T extends Card> {
private List<T> cards;
public Deck () {
cards = new ArrayList()<>;
}
}
现在,要回答您的问题,您应该首先回到Java的一些基础知识:
Now, to answer your question you should go back to some basics first in java:
1-数组是协变构造
2-泛型是不变的构造
2- Generics are invariant constructs
3-元素类型在数组中进行分类(分类)
3- Element Type is reified in arrays (reification)
4-通用(删除类型)中的参数类型
4- Parameter Type is erased in Generic (Type erasure)
不用担心,让我们放下一些可怕的概念,并检查一下示例所发生的情况:
No worries, let put aside scary concepts, and check what happened with your example:
-
正式类型T在运行时被删除.
The Formal type T is erased in Runtime.
这意味着它已在字节码中完全删除.
It means it's completely removed in the bytecode.
在第一个示例中,T仅被Object取代,因为它是最接近它的类(就继承而言)所以,
In 1st example the T is just replaced with Object, because it's the nearest class to it (in terms of inheritance) so,
cards = (T []) new Object[52]
已翻译为
cards = (Object []) new Object[52];
这是安全的.
- 在第二个示例中,T绑定到Card,它变成,因此,它是最接近它的类(就继承而言)因此,
cards = (T []) new Object[52]
被翻译为
cards = (Card []) new Object[52];
由于Object不是Card的子类型,因此您遇到了运行时强制转换异常.
Since Object is not a subtype of Card, you got a Runtime cast exception.
这篇关于为什么" java.lang.ClassCastException:[Ljava.lang.Object;无法转换为“有界类型参数而不是形式类型参数错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!