使用[] call

时间:2017-11-30 17:42:37

标签: java reflection libgdx kotlin

我正在为我的游戏使用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 Array不是来自Kotlin。

val animation = Animation(Array.with(TextureRegion(Texture("badlogic.jpg"))))

你能告诉我这种情况发生的原因还是可能是一个错误?

1 个答案:

答案 0 :(得分:5)

修改:在早期版本的libGDX中,Animation不使用Array的反射功能。如果 ,则不会出现此错误,因为数组的类型正确!它应该在版本1.9.7中的libGDX中。注意:创建时必须指定Class的{​​{1}}。

最近在#4476修正了此问题。 但是,以下&#34; bug&#34;使用Arrayget导致数组的不同字节码仍然值得报告/查询。

这很有趣!

反编译

[]

给出

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 tex1 = animation.keyFrames.get(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

请务必注意val tex = animation.keyFrames[0] 的类型为keyFrames,因此无法使用自定义T[]方法(假设不存在扩展名。)

虽然the two should be equalget会调用[]),但它们似乎不是!

我能看到的唯一区别是operator fun get变体在通过get检索后检查了类型(CHECKCAST),而AALOAD变体尝试检查检索数组后,数组的类型为[]

但是,因为在T[]的构造函数中声明了frames

Animation

as

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[]失败了。

对我而言,这似乎是一个libGDX错误。

我可以使用Java中的一个简单类来轻松地重现它:

TextureRegion[]

这也会在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[]。因此,这些&#34;泛型&#34;不应该暴露数组我可以理解为什么libGDX会这样做,即提高性能并消除方法调用的小开销,但这绝对不安全。

Object[]get不同的事实可能是一个错误。也许查看这个或提交错误报告可能有所帮助。

Java bytecode instruction list