由于 java 没有通用数组,因此我使用将对象数组转换为类型参数的常规技巧。当我有一个像这样的正式类型参数时,这工作得很好<T>
但当我使用有界类型参数时则不然<T extends something>
.
使用正式类型遵循代码效果很好
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 {
}
以下使用有界类型的代码会引发错误
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)
这个例子让我想起了早期,当我在“Effective java”一书中阅读有关泛型的内容时......
首先,这是java泛型的黄金法则:不要混合数组和泛型,因为你有很好的机会生成不安全的代码。
您的代码将泛型(例如 T、T extends Card)与数组(例如 T [] 卡)混合在一起。然后,您在运行时得到不安全的代码。
这是一种安全的方法(首选列表而不是数组):
class Deck <T extends Card> {
private List<T> cards;
public Deck () {
cards = new ArrayList()<>;
}
}
现在,要回答你的问题,你应该首先回到 java 的一些基础知识:
1- 数组是共变结构
2-泛型是不变的结构
3-元素类型在数组中具体化(reification)
4- 参数类型在通用中被擦除(类型擦除)
不用担心,先把可怕的概念放在一边,看看你的例子发生了什么:
cards = (T []) new Object[52]
被翻译成
cards = (Object []) new Object[52];
这是安全的。
- 在第二个示例中, T 绑定到 Card ,因此它成为最接近它的类(就继承而言)
所以,
cards = (T []) new Object[52]
被翻译成
cards = (Card []) new Object[52];
由于 Object 不是 Card 的子类型,因此您遇到了运行时强制转换异常。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)