繁体   English   中英

为什么“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 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”一书中阅读 Generics 时......

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. 您的代码将 generics(例如 T、T 扩展卡)与 arrays(例如 T [] 卡)混合在一起。 然后,你在运行时得到了不安全的代码。

这是一种安全的方法(更喜欢列表而不是数组):

class Deck <T extends Card> {
    private List<T> cards;

    public Deck () {
        cards = new ArrayList()<>;
    }

}

现在,要回答您的问题,您应该首先在 go 回到 java 中的一些基础知识:

1- Arrays 是协变结构

2- Generics 是不变结构

3-元素类型在 arrays 中具体化(具体化)

4- 参数类型在 Generic 中被擦除(类型擦除)

不用担心,抛开可怕的概念,看看你的例子发生了什么:

  • 正式类型 T 在运行时被擦除。

  • 这意味着它已在字节码中完全删除。

  • 在第一个示例中,T 刚刚替换为 Object,因为它是最接近它的 class(就继承而言)所以,

cards = (T []) new Object[52]

被翻译成

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

这是安全的。

  • 在第二个示例中, T 绑定到 Card ,因此它成为最接近它的 class (就继承而言),所以,
cards = (T []) new Object[52]

被翻译成

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

由于 Object 不是 Card 的子类型,因此您遇到了运行时强制转换异常。

暂无
暂无

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

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