繁体   English   中英

使用[]调用时出现奇怪的java.lang.ClassCastException

[英]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时必须指定ArrayClass

最近在#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[]不同的事实可能是一个错误。 也许查看这个或提交错误报告可能会有所帮助。


Java字节码指令列表

暂无
暂无

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

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