具有通用varargs的ClassCastException?

时间:2019-10-12 14:54:49

标签: java generics

我有一个通用接口

{
void evaluate( TYPE... things );
}

我有一个带有签名的通用方法

<TYPE> void genericmethod( INTERFACE<TYPE> interfase, TYPE thing )
{
//the following line throws the ClassCastException
interfase.evaluate( thing );
}

PCard是我项目中的名字。

所以最后的电话是

INTERFACE<PCard> interfase = new WorkingImplementation<PCard>();
PCard pcard = new PCard();

这似乎在泛型方法中引发ClassCastException,当它尝试调用时将单个pcard转换为varargs数组。

genericmethod( interfase, pcard );

当不调用泛型方法而您直接调用接口时,该问题得到缓解。

interfase.evaluate( pcard );

是什么原因(内部)导致异常? (我个人的猜测是Java不堪重负)

异常消息:

java.lang.ClassCastException:类[Ljava.lang.Object;不能转换为类[Llib.cardgame.CG $ PCard; ([Ljava.lang.Object;位于加载程序'bootstrap'的模块java.base中; [Llib.cardgame.CG $ PCard;位于加载程序'app'的未命名模块中)

1 个答案:

答案 0 :(得分:1)

简短的回答:泛型和数组不能混合使用。请改用List<? extends TYPE> things

泛型仅仅是编译器的把戏。它们在运行时不存在。数组在运行时具有不同的类型,例如String[]Number[]。但是,由于在运行时不存在泛型类型,因此编译器无法生成将生成泛型类型的数组的代码。 (对varargs方法的调用会隐式创建一个数组来保存varargs参数。)

在您的情况下,编译器会对此发出警告,并生成与您想要的代码尽可能接近的代码:每当调用varargs方法时,为隐式数组生成的代码将为{{1} }(自Object[]起,我猜没有上限)。

如果打开所有编译器警告,则会收到通知。正确解决所有编译器警告(即,不要使用TYPE)将确保您不会像现在看到的那样获得令人惊讶的惊喜。

我推荐Gilad Bracha’s generics tutorial。我发现它对于了解泛型的工作原理非常重要。