문제

나는 여기서 모르는 미묘한 일이 있어야한다고 생각합니다. 다음을 고려하세요:

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA() {
    return a;
  }
}

주요 방법이 다음을 포함한다고 가정합니다.

Foo<Double> f = new Foo<Double>();
Double[] d = f.getA();

당신은 얻을 것입니다 CastClassException 메시지와 함께 java.lang.Object 캐스트 할 수 없습니다 java.lang.Double.

누구든지 이유를 말해 줄 수 있습니까? 내 이해 ClassCastException 캐스트 할 수없는 유형에 물체를 캐스팅하려고 할 때 던져진 것입니다. 즉, 서브 클래스는 인스턴스가 아닌 (문서를 인용하기 위해). 예 :

Object o = new Double(3.);
Double d = (Double) o; // Working cast
String s = (String) o; // ClassCastException

그리고 내가 이것을 할 수있는 것 같습니다. 만약에 a 그냥 a T 배열 대신 T[], 우리는 얻을 수 있습니다 a 문제없이 캐스팅하십시오. 왜 배열이 이것을 깨뜨리는가?

감사.

도움이 되었습니까?

해결책

Foo<Double> f = new Foo<Double>();

이 버전의 일반 클래스 foo를 사용하면 멤버 변수에 대해 a, 컴파일러는 본질적 으로이 라인을 취하고 있습니다.

private T[] a = (T[]) new Object[5];

그리고 교체 T ~와 함께 Double 이것을 얻으려면 :

private Double[] a = (Double[]) new Object[5];

물체에서 두 배로 캐스트 할 수 없으므로 ClassScastException.

업데이트 및 설명 : 실제로, 일부 테스트 코드를 실행 한 후 ClasscastException은 이것보다 더 미묘합니다. 예를 들어,이 주요 방법은 예외없이 잘 작동합니다.

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    System.out.println(f.getA());
}

할당을 시도 할 때 문제가 발생합니다 f.getA() 유형의 참조 Double[]:

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    Double[] a2 = f.getA(); // throws ClassCastException
    System.out.println(a2);
}

이는 멤버 변수에 대한 유형 정보가 있기 때문입니다 a 런타임에 지워집니다. 제네릭은 유형 안전성 만 제공합니다 컴파일 타임 (나는 어떻게 든 초기 게시물에서 이것을 무시하고있었습니다). 따라서 문제는 아닙니다

private T[] a = (T[]) new Object[5];

런타임 에이 코드는 실제로 이루어지기 때문입니다

private Object[] a = new Object[5];

문제는 방법 결과가 발생할 때 발생합니다 getA(), 런타임에 실제로 반환합니다 Object[], 유형의 참조에 할당됩니다 Double[] -이 명령문은 객체를 두 배로 캐스트 할 수 없기 때문에 ClassCastException을 던집니다.

업데이트 2: 마지막 질문에 대답하기 위해 "왜 배열이 이것을 깨뜨리는가?" 답은 언어 사양이 일반 어레이 생성을 지원하지 않기 때문입니다. 자세한 내용은이 포럼 게시물을 참조하십시오 - 거꾸로 호환 되려면 런타임의 T 유형에 대해서는 알려진 바가 없습니다.

다른 팁

@mattb의 설명에는 약간의 오류가있을 수 있습니다.

오류는입니다 ~ 아니다

java.lang.object는 java.lang.double에 캐스트 할 수 없습니다.

그것은이다:

ljava.lang.object; [ljava.lang.double에 캐스트 할 수 없습니다

l은 배열을 의미합니다. 즉, 오류는 an입니다 정렬 객체의 객체는 이중 배열로 캐스트 할 수 없습니다. 이것은 다음과 같은 경우입니다.

Object[] oarr = new Object[10];
Double[] darr = (Double[]) oarr;

이것은 분명히 허용되지 않습니다.

TypeSafe 배열을 만드는 문제의 경우, 또 다른 대안은 init 및 array.newinstance를 사용하는 클래스 객체를 제외한 것입니다.

import java.lang.reflect.Array;

class Foo<T> {
  private T[] a ;

  public Foo(Class<T> tclass) {
    a = (T[]) Array.newInstance(tclass, 5);
  }

  public T[] getA() {
    return a;
  }

  public static <T> Foo<T> create(Class<T> tclass) {
    return new Foo<T>(tclass);
  }
}

class Array1
{
  public static final void main(final String[] args) {
    Foo<Double> f = Foo.create(Double.class);
    Double[] d = f.getA();
  }


}

@Matt B : 답변 해주셔서 감사합니다! 매우 도움이됩니다.

관심있는 사람들을위한 해결 방법을 찾았습니다. Geta 방법에 초기화 된 배열을 채우십시오. 이렇게하면 유형 정보를 사용할 수 있습니다.

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA(T[] holdA) {
    // Check whether holdA is null and handle it...then:
    holdA = (T[]) Array.newInstance(holdA.getClass().getComponentType(), a.length);
    System.arraycopy(a, 0, holdA, 0, a.length);
    return holdA;
  }
}

그런 다음 주요 방법을 위해 :

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top