使用[]调用时出现奇怪的java.lang.ClassCastException [英] Strange java.lang.ClassCastException when using [] call
问题描述
我正在为游戏使用LibDGX库.而且我遇到了常见的异常ClassCastException
,但是它发生在奇怪的情况下.
I'm using LibDGX library for my game. And i faced common exception ClassCastException
, but it occurs in strange case.
I'm using Animation class from LibGDX library.
仅当我使用[]
操作时,我在此行上出现错误.
I'm getting error on this line only if i am using []
operation.
val tex = animation.keyFrames[0]
如果我将其更改为get()
错误消失.
tex = animation.keyFrames.get(0)
这是完整的方法.我简化了示例.
Here is full method. I simplified example.
override fun create() {
val frames = Array<TextureRegion>()
frames.add(TextureRegion(Texture("badlogic.jpg")))
val animation = Animation(frames)
val tex1 = animation.keyFrames.get(0) // Compiles
val tex = animation.keyFrames[0] // error - [Ljava.lang.Object; cannot be cast to [Lcom.badlogic.gdx.graphics.g2d.TextureRegion;
}
奇怪,不是吗?
这是我用来最小化其他错误原因的Animation类.与LibGDX api中的相同.
Here is Animation class that i used to minimise other error reasons. It is the same as in LibGDX api.
public class Animation<T> {
T[] keyFrames;
private float frameDuration;
public Animation (float frameDuration, Array<? extends T> keyFrames) {
this.frameDuration = frameDuration;
Class arrayType = keyFrames.items.getClass().getComponentType();
T[] frames = (T[]) ArrayReflection.newInstance(arrayType, keyFrames.size);
for (int i = 0, n = keyFrames.size; i < n; i++) {
frames[i] = keyFrames.get(i);
}
setKeyFrames(frames);
}
protected void setKeyFrames (T... keyFrames) {
this.keyFrames = keyFrames;
}
}
我还注意到,如果我使用Array.with
构造而不是创建Array<TextureRegion>
,则错误消失,我的意思是LibGDX
I also noticed that error disappears if i use Array.with
construction instead of creating Array<TextureRegion>
I mean LibGDX Array not from Kotlin.
val animation = Animation(Array.with(TextureRegion(Texture("badlogic.jpg"))))
您能否告诉我发生这种情况的原因,或者可能是错误?
Could you tell me the reason why this occurs or it is possible a bug?
推荐答案
编辑:在旧版本的libGDX中,Animation
不使用Array
的反射功能.如果它有,则不会出现此错误,因为数组的类型正确!它应该在1.9.7版本的libGDX中.注意:创建Array
时必须指定Class
.
Edit: In older versions of libGDX, Animation
does not use Array
's reflection capabilities. If it had, you wouldn't have this error, because the array would be of the correct type! It should be in libGDX in version 1.9.7. Note: you must specify the Class
of the Array
when creating it.
最近在#4476 中已修复此问题.
但是,以下带有get
和[]
的错误"可能导致数组的字节码不同,仍然值得报告/查询.
This was fixed recently in #4476.
However, the following "bug" with get
and []
resulting in different bytecode for an array may still be worth reporting/inquiring about.
这很有趣!
反编译
val tex1 = animation.keyFrames.get(0)
给予
ALOAD 2
INVOKEVIRTUAL com/badlogic/gdx/graphics/g2d/Animation.getKeyFrames ()[Ljava/lang/Object;
ICONST_0
AALOAD
CHECKCAST com/badlogic/gdx/graphics/g2d/TextureRegion
ASTORE 3
反编译时
val tex = animation.keyFrames[0]
给予
ALOAD 2
INVOKEVIRTUAL com/badlogic/gdx/graphics/g2d/Animation.getKeyFrames ()[Ljava/lang/Object;
CHECKCAST [Lcom/badlogic/gdx/graphics/g2d/TextureRegion;
ICONST_0
AALOAD
ASTORE 4
重要的是要注意,keyFrames
的类型是T[]
,因此它不可能具有自定义的get
方法(假设不存在扩展名.)
It is important to note that the type of keyFrames
is T[]
, so it cannot possibly have a custom get
method (assuming no extensions exist.)
尽管这两个应该等于([]
调用operator fun get
),不是!
It seems that although the two should be equal ([]
invokes operator fun get
), they are not!
我唯一看到的区别是get
变体通过AALOAD
检索后检查类型(CHECKCAST
),而[]
变体尝试检查数组的类型是否为
The only difference I can see is that the get
variant checks the type (CHECKCAST
) after retrieving it via AALOAD
, while the []
variant attempts to check that the type of the array is T[]
immediately after retrieving the array.
但是,因为frames
是在Animation
的构造函数中声明的:
However, because frames
is declared in Animation
's constructor:
public Animation (float frameDuration, Array<? extends T> keyFrames) {
this.frameDuration = frameDuration;
T[] frames = (T[]) new Object[keyFrames.size];
for (int i = 0, n = keyFrames.size; i < n; i++) {
frames[i] = keyFrames.get(i);
}
setKeyFrames(frames);
}
为
T[] frames = (T[]) new Object[keyFrames.size];
该数组的实际类型为Object[]
!因此,此强制转换为TextureRegion[]
失败.
在我看来,这似乎是一个libGDX错误.
To me, this seems like a libGDX bug.
我可以使用Java中的一个简单类很容易地重现此内容:
I am able to very easily reproduce this with a simple class in Java:
public class JavaObjWithArray<T> {
private T[] items;
public JavaObjWithArray(T[] items) {
this.items = (T[]) new Object[items.length];
System.arraycopy(items, 0, this.items, 0, items.length);
}
public T[] getItems() {
return items;
}
}
fun main(args: Array<String>) {
val obj = JavaObjWithArray(arrayOf("a", "b"))
val one = obj.items.get(0)
val two = obj.items[0]
}
这还将在[]
的行上抛出ClassCastException
!此外,字节码具有相同的区别.
This will also throw a ClassCastException
on the line with []
! Additionally, the bytecode has the same difference.
该问题实际上是由于Java(和Kotlin)缺少通用数组而引起的. Java有两种主要的解决方案:
The problem really arises with the lack of generic arrays in Java (and Kotlin). There are two main solutions for this in Java:
- 存储
Object[]
并将值强制转换为get
- 存储
Object[]
,但将其强制转换为T[]
- Store an
Object[]
and cast the values uponget
- Store an
Object[]
, but cast it toT[]
这是一个问题-因为数组的实际类型是 Object[]
.因此,这些通用"数组不应公开!我可以理解libGDX为何这样做,即提高性能并消除方法调用的少量开销,但这绝对是不安全的.
This is a problem - because the actual type of the array is Object[]
. As a consequence, these "generic" arrays should not be exposed! I can understand why libGDX does so, namely, to improve performance and remove the small overhead of method calls, but this is definitely not safe.
get
和[]
不同的事实 可能是一个错误.也许调查一下或提交错误报告可能会有所帮助.
The fact that get
and []
differ may be a bug, though. Perhaps looking into this or filing a bug report may help.
这篇关于使用[]调用时出现奇怪的java.lang.ClassCastException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!