다음은 제네릭을 사용하여 형식 안전을 유지하면서 찾고있는 형식의 배열을 얻는 방법입니다 (다른 답변과 달리 Object배열 을 반환 하거나 컴파일 타임에 경고를 표시 함).
import java.lang.reflect.Array;
public class GenSet<E> {
private E[] a;
public GenSet(Class<E[]> clazz, int length) {
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
}
public static void main(String[] args) {
GenSet<String> foo = new GenSet<String>(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
}
}
당신이 볼 수있는 경고없이 컴파일하고, 같은 main당신의 인스턴스 선언 어떤 유형, GenSet등, 당신은 할당 할 수있는 a해당 유형의 배열에, 당신은에서 요소를 할당 할 수 a배열 즉, 해당 유형의 변수 배열의 값이 올바른 유형입니다.
Java Tutorials 에서 설명한 것처럼 클래스 리터럴을 런타임 유형 토큰으로 사용하여 작동합니다 . 클래스 리터럴은 컴파일러에서의 인스턴스로 처리됩니다 java.lang.Class. 하나를 사용하려면으로 클래스 이름을 따르십시오 .class. 따라서 클래스를 나타내는 객체 String.class로 작동 Class합니다 String. 또한 인터페이스, 열거 형, 모든 차원 배열 (예 :) String[].class, 프리미티브 (예 :) int.class및 키워드 void(예 :)에서도 작동합니다 void.class.
Class자체는 일반적입니다 (로 선언 Class<T>, 여기서 객체가 나타내는 T유형을 Class나타냄) . 의 유형은 String.class입니다 Class<String>.
따라서에 대한 생성자를 호출 할 때마다 인스턴스의 선언 된 유형의 GenSet배열을 나타내는 첫 번째 인수에 대해 클래스 리터럴을 전달 GenSet합니다 (예 : String[].classfor GenSet<String>). 프리미티브는 유형 변수에 사용할 수 없기 때문에 프리미티브 배열을 얻을 수 없습니다.
생성자 내에서 메서드를 호출하면 메서드 cast가 호출 Object된 Class객체가 나타내는 클래스로 전달 된 인수가 반환 됩니다. 정적 메소드 newInstance를 호출하면 첫 번째 인수로 전달 된 객체와 두 번째 인수로 전달 된 길이로 표시되는 유형의 배열이 java.lang.reflect.Array반환됩니다 . 메소드 호출 복귀 어레이의 구성 형태를 나타내는 객체에 의해 표현 (예를 들어 메소드가 호출되는 객체 에 대해 , 경우 생성 객체 배열을 나타내지 않음).ObjectClassintgetComponentTypeClassClassString.classString[].classnullClass
마지막 문장은 완전히 정확하지 않습니다. 호출 String[].class.getComponentType()반환 Class클래스를 나타내는 객체 String, 그러나 그것의 유형입니다 Class<?>하지, Class<String>당신은 다음과 같은 일을 할 수없는 이유이다.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
객체 Class를 반환하는 모든 메소드에 동일하게 적용됩니다 Class.
이 답변에 대한 Joachim Sauer의 의견에 대해 (나는 스스로 의견을 제시 할만큼 평판이 충분하지 않습니다), 캐스트를 사용하는 예제 T[]는 컴파일러가 유형 안전을 보장 할 수 없기 때문에 경고를 표시합니다.
Ingo의 의견에 관한 편집 :
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}