使用[]调用时出现奇怪的java.lang.ClassCastException [英] Strange java.lang.ClassCastException when using [] call

查看:95
本文介绍了使用[]调用时出现奇怪的java.lang.ClassCastException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为游戏使用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 upon get
  • Store an Object[], but cast it to T[]

这是一个问题-因为数组的实际类型是 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字节码指令列表

这篇关于使用[]调用时出现奇怪的java.lang.ClassCastException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆