![](/img/trans.png)
[英]java.lang.ClassCastException when using custom classloader
[英]Strange java.lang.ClassCastException when using [] call
我正在为我的游戏使用LibDGX库。 我遇到了常见的异常ClassCastException
,但它出现在奇怪的情况下。
我正在使用LibGDX库中的Animation类。
只有当我使用[]
操作时,我才会在此行上出错。
val tex = animation.keyFrames[0]
如果我将其更改为get()
错误消失 。
tex = animation.keyFrames.get(0)
这是完整的方法。 我简化了例子。
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中的相同。
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 数组不是来自Kotlin。
val animation = Animation(Array.with(TextureRegion(Texture("badlogic.jpg"))))
你能告诉我出现这种情况的原因还是可能是一个错误?
编辑 :在旧版本的libGDX中, Animation
不使用Array
的反射功能。 如果有 ,你就不会有这个错误,因为数组的类型是正确的! 它应该在版本1.9.7中的libGDX中。 注意:创建Array
时必须指定Array
的Class
。
最近在#4476修复了这个问题。 但是,以下带有get
和[]
“bug”导致数组的不同字节码仍然值得报告/查询。
这是有趣的!
反编译
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
方法(假设不存在扩展名。)
似乎虽然两者应该相等 ( []
调用operator fun get
),但它们不是!
我可以看到,唯一的区别是, get
变体检查类型( CHECKCAST
通过检索它之后) AALOAD
,而[]
变体试图检查阵列的类型是T[]
检索阵列之后 。
但是,因为frames
是在Animation
的构造函数中声明的:
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错误。
我可以使用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
! 此外,字节码具有相同的差异。
问题确实出现在Java(和Kotlin)中缺少通用数组。 Java中有两种主要的解决方案:
Object[]
并在get
值 Object[]
,但将其强制转换为T[]
这是一个问题 - 因为数组的实际类型是 Object[]
。 因此, 不应暴露这些“通用”阵列! 我可以理解为什么libGDX会这样做,即提高性能并消除方法调用的小开销,但这绝对不安全。
但是, get
和[]
不同的事实可能是一个错误。 也许查看这个或提交错误报告可能会有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.