ica*_*bas 3 java reflection libgdx kotlin
我正在为我的游戏使用LibDGX库.我遇到了常见的异常ClassCastException,但它发生在奇怪的情况下.
我正在使用LibGDX库中的Animation类.
只有在我使用操作时,我才会在此行上出错.[]
val tex = animation.keyFrames[0]
Run Code Online (Sandbox Code Playgroud)
如果我将其更改为get() 错误消失.
tex = animation.keyFrames.get(0)
Run Code Online (Sandbox Code Playgroud)
这是完整的方法.我简化了例子.
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;
}
Run Code Online (Sandbox Code Playgroud)
奇怪,不是吗?
这是我用来最小化其他错误原因的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;
}
}
Run Code Online (Sandbox Code Playgroud)
我还注意到,如果我使用构造而不是创建我的意思是LibGDX 数组而不是来自Kotlin ,则错误消失.Array.withArray<TextureRegion>
val animation = Animation(Array.with(TextureRegion(Texture("badlogic.jpg"))))
Run Code Online (Sandbox Code Playgroud)
你能告诉我出现这种情况的原因还是可能是一个错误?
编辑:在旧版本的libGDX中,Animation不使用Array反射功能.如果有,你就不会有这个错误,因为数组的类型是正确的!它应该在版本1.9.7中的libGDX中.注意:您必须指定Class的Array创建时.
最近在#4476修复了这个问题.但是,以下"错误" get并[]导致阵列的不同字节码仍然值得报告/查询.
这是有趣的!
反编译
val tex1 = animation.keyFrames.get(0)
Run Code Online (Sandbox Code Playgroud)
给
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]
Run Code Online (Sandbox Code Playgroud)
给
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在检索后通过检查type()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);
}
Run Code Online (Sandbox Code Playgroud)
如
T[] frames = (T[]) new Object[keyFrames.size];
Run Code Online (Sandbox Code Playgroud)
数组的实际类型是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]
}
Run Code Online (Sandbox Code Playgroud)
这也将抛出一条ClassCastException线[]!此外,字节码具有相同的差异.
问题确实出现在Java(和Kotlin)中缺少通用数组.Java中有两种主要的解决方案:
Object[]并投射值getObject[],但将其投射到T[]这是一个问题 - 因为数组的实际类型是 Object[].因此,不应暴露这些"通用"阵列!我可以理解为什么libGDX会这样做,即提高性能并消除方法调用的小开销,但这绝对不安全.
这样的事实get和[]不同,可能是一个错误,但.也许查看这个或提交错误报告可能会有所帮助.
| 归档时间: |
|
| 查看次数: |
399 次 |
| 最近记录: |