2017-11-30 9 views
3

내 게임에 LibDGX 라이브러리를 사용하고 있습니다. 그리고 나는 일반적인 예외 ClassCastException에 직면하지만 이상한 경우에 발생합니다.[] 호출을 사용할 때 이상한 java.lang.ClassCastException

저는 LibGDX 라이브러리의 Animation 클래스를 사용하고 있습니다.

[] 작업을 사용하는 경우에만이 줄에 오류가 표시됩니다. 내가 get()오류로 변경하는 경우

val tex = animation.keyFrames[0] 

을 사라집니다.

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; 


} 

이상한가요?

다른 오류 이유를 최소화하는 데 사용한 애니메이션 클래스는 다음과 같습니다. LibGDX api에서와 동일합니다. 내가하지 코 틀린에서 LibGDX Array을 의미 대신 Array<TextureRegion>을 만드는 Array.with 건설을 사용하는 경우 나 또한 그 오류 을 발견

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; 
    } 
} 

을 사라집니다. 이 문제가 발생하거나 버그 가능한 이유

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

당신은 나에게 이유를 말씀해 주시겠습니까?

+0

이것은 동일한 'Animation' 클래스 ['Animation' (아니다 https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/ graphics/g2d/Animation.html)에이 생성자가 없습니다. – Moira

+0

@ 1blustone 좋아, 이제 좋니? 그러나 그것은 이해가되지 않습니다 ... 나는 더 읽기 쉽게하려고 노력했습니다. 오류가 발생합니다. – icarumbas

+0

아, 지금은 이해가됩니다.현재 소스가 아직 공개되지 않은 상태입니다. 이 버그가 수정 될 것으로 보인다 다음 릴리스에서 내 대답을 참조하십시오 :) – Moira

답변

5

편집 : libGDX의 이전 버전에서 AnimationArray의 리플렉션 기능을 사용하지 않습니다. 이있는 경우이 배열은 올바른 유형이므로이 오류가 발생하지 않습니다! 버전 1.9.7의 libGDX에 있어야합니다. 참고 : 만들 때 ArrayClass을 지정해야합니다.

최근 수정 된 주소는 #4476입니다. 그러나 get[]의 "버그"로 인해 배열의 바이트 코드가 다른 경우에도보고/문의 할 가치가 있습니다.


이것은 흥미 롭습니다! 디 컴파일

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 방법을 사용할 수 없습니다 (확장이 없다고 가정).)

the two should be equal ([]operator fun get을 호출하지만) 그렇지 않습니다. I 보시

유일한 차이점은 [] 변형 배열의 형 배열 입수 직후 T[]인지 확인하려고 시도하면서 get 변형, AALOAD 통해 입수 후 유형 (CHECKCAST)를 확인한다는 것이다.

그러나 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 버그처럼 보입니다.


나는 아주 쉽게 자바 간단한 클래스와 함께이 문제를 재현 할 수 있어요 :

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)의 일반 배열이 부족하여 문제가 발생합니다. 이이 두 가지의 주요 솔루션은 자바에 있습니다 Object[]

  • 저장 및 get
  • 스토어 Object[]에 값을 던져하지만 T[]

이로 캐스팅 문제가합니다 - 있기 때문에 배열 의 실제 유형은Object[]입니다. 결과적으로 이러한 "일반적인"배열 은 노출되어서는 안됩니다! libGDX가 그렇게하는 이유, 즉 성능을 향상시키고 메소드 호출의 작은 오버 헤드를 제거하는 이유를 이해할 수 있습니다. 그러나 이것은 확실히 안전하지 않습니다.


get[] 비록 버그 다를 수도 있다는 사실. 아마 이것을 조사하거나 버그 보고서를 제출하는 것이 도움이 될 수 있습니다.


Java bytecode instruction list

+0

좋은 설명 주셔서 감사합니다. 그것은 정말로 도움이되었습니다. 이 질문은 오랫동안 나를 괴롭혔다. 이제 우리는 마침내 이것이 코 틀린 벌레라고 결정했습니다. 그럼 내가 문제를 만든다. – icarumbas

+0

@icarumbas'[]'와'get'이있는 부분은 그렇게 보입니다. 또한 문서에는'[] '와'operator get'이 같은 효과를 가져야한다고 명시되어 있습니다. '[] '에 대한 IntelliJ 문서는'get'으로 연결됩니다. – Moira

+0

여기서 얻은 특정 'ClassCastException'은 Kotlin 버그가 아니기 때문에 [libGDX with Java를 사용하는 경우에도이 예외를 얻을 수 있습니다] (https://github.com/libgdx/libgdx/issues/4476) 때문입니다. – Moira