为什么;java.lang.ClassCastException:[Ljava.lang.Object;不能对有界类型参数而不是形式类型参数强制转换为“错误”?

为什么;java.lang.ClassCastException:[Ljava.lang.Object;不能对有界类型参数而不是形式类型参数强制转换为“错误”?,java,generics,classcastexception,Java,Generics,Classcastexception,由于java没有泛型数组,所以我使用了将对象数组强制转换为类型参数的常规技巧。当我有一个像这样的正式类型参数时,这种方法可以很好地工作,但当我使用有界类型参数时就不行了 下面的代码使用正式类型很好 public class Deck <T> { private T [] cards; private int size; public Deck () { cards = (T []) new Object[52]; size =

由于java没有泛型数组,所以我使用了将对象数组强制转换为类型参数的常规技巧。当我有一个像
这样的正式类型参数时,这种方法可以很好地工作,但当我使用有界类型参数
时就不行了

下面的代码使用正式类型很好

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 {
}
公共类甲板{
私人T[]卡;
私有整数大小;
公共甲板(){
cards=(T[])新对象[52];
尺寸=0;
}
}
公共类黑杰克游戏{
甲板;
公共黑杰克游戏(){
甲板=新甲板();
填充(甲板);
洗牌();
}
}
公共级黑卡扩展卡{
}
下面使用有界类型的代码抛出错误

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)
公共类甲板{
私人T[]卡;
私有整数大小;
公共甲板(){
cards=(T[])新对象[52];
尺寸=0;
}
}
公共类黑杰克游戏{
甲板;
公共黑杰克游戏(){
甲板=新甲板();
填充(甲板);
洗牌();
}
}
公共级黑卡扩展卡{
}
线程“main”java.lang.ClassCastException中的异常:[Ljava.lang.Object;无法转换为[LCard;
在甲板上。(Deck.java:10)
在BlackJackGame。(BlackJackGame.java:5)

这个例子让我想起了早期,当我在《有效java》一书中阅读泛型时

首先,这里是java泛型的黄金法则:不要混合使用数组和泛型,因为这样很有可能产生不安全的代码。 您的代码将泛型(例如T、T扩展卡)与数组(例如T[]卡)混合在一起,然后在运行时得到不安全的代码

这是一种安全的方法(首选列表而不是数组):

翻译成

cards = (Object []) new Object[52];
这是安全的

  • 在第二个示例中,T与卡绑定,因此它成为离它最近的类(就继承而言) 所以
翻译成

cards = (Card []) new Object[52];

由于对象不是卡的子类型,因此出现了运行时强制转换异常。

查找“类型擦除”然后,什么
被擦除,什么
被擦除。这将帮助您理解主题并理解这里的问题。第二个副本可能重复,包括有界类型和原始类型:现在您知道为什么编译器标记
(T[])
为“未选中强制转换”警告。该强制转换不安全。您不允许使用列表吗?请您详细说明一下,为什么java在添加强制转换时会执行“最近的类”操作?
cards = (Object []) new Object[52];
cards = (T []) new Object[52]
cards = (Card []) new Object[52];