为什么" 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?

查看:106
本文介绍了为什么" java.lang.ClassCastException:[Ljava.lang.Object;无法转换为“有界类型参数而不是形式类型参数错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于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.

这篇关于为什么&quot; java.lang.ClassCastException:[Ljava.lang.Object;无法转换为“有界类型参数而不是形式类型参数错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆