일반 매개 변수의 유형을 얻을 수 있습니까?
예를 들면 :
public final class Voodoo {
public static void chill(List<?> aListWithTypeSpiderMan) {
// Here I'd like to get the Class-Object 'SpiderMan'
Class typeOfTheList = ???;
}
public static void main(String... args) {
chill(new ArrayList<SpiderMan>());
}
}
답변
하나의 구조, 나는 한 번 넘어졌다
Class<T> persistentClass = (Class<T>)
((ParameterizedType)getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
불행히도 완전히 이해하지 못하는 주변에 반성 마법이있는 것 같습니다 … 미안합니다.
답변
@DerMike의 답변을 세분화하여 설명하려고합니다.
첫째, 유형의 삭제는 그 JDK의 의미하지 않는다 을 제거해을 가 런타임에 유형 정보를 . 컴파일 타임 유형 검사 및 런타임 유형 호환성이 동일한 언어로 공존 할 수 있도록하는 방법입니다. 이 코드 블록에서 알 수 있듯이 JDK는 지워진 유형 정보를 유지합니다. 이는 확인 된 캐스트 및 항목과 관련이 없습니다.
둘째, 이것은 검사중인 콘크리트 유형에서 계층 구조의 정확히 한 레벨 위의 일반 클래스에 일반 유형 정보를 제공합니다. 그 으로부터 직접 상속받습니다. 이 클래스가 비 추상적이고 인스턴스화되었거나 구체적인 구현이 두 수준 아래로 내려간 경우에는 작동하지 않습니다 (조금의 약간의 지미로 인해 하나 이상의 클래스 또는 가장 낮은 클래스까지 미리 정해진 수의 레벨에 적용 할 수 있음) X 제네릭 형식 매개 변수 등).
어쨌든, 설명에. 다음은 쉽게 참조 할 수 있도록 코드를 다시 한 줄로 분리 한 것입니다.
1 # 클래스 genericParameter0OfThisClass = 2 # (클래스) 3 # ((매개 변수화 된 유형) 4 # getClass () 5 # .getGenericSuperclass ()) 6 # .getActualTypeArguments () [0];
이 코드를 포함하는 제네릭 형식의 추상 클래스 인 ‘us’를 보자. 이것을 대략 내부에서 읽는다.
- 4 행은 현재 구체적 클래스의 Class 인스턴스를 가져옵니다. 이것은 우리의 직계 후손의 구체적인 유형을 식별합니다.
- 5 행은 해당 클래스의 수퍼 타입을 유형으로 가져옵니다. 이것은 우리입니다. 우리는 파라 메트릭 타입이기 때문에 안전하게 ParameterizedType (라인 3)으로 캐스팅 할 수 있습니다. 핵심은 Java가이 Type 개체를 결정할 때 자식에있는 형식 정보를 사용하여 형식 정보를 새 ParameterizedType 인스턴스의 형식 매개 변수와 연결한다는 것입니다. 이제 제네릭의 구체적인 유형에 액세스 할 수 있습니다.
- 6 행은 클래스 코드에 선언 된 순서대로 제네릭에 매핑 된 형식의 배열을 가져옵니다. 이 예에서는 첫 번째 매개 변수를 뽑습니다. 이것은 유형으로 돌아옵니다.
- 2 행은 클래스에 반환 된 최종 Type을 캐스팅합니다. 우리는 제네릭 형식 매개 변수가 취할 수있는 유형을 알고 있으며 모두 유형이 될 것임을 확인할 수 있기 때문에 안전합니다 (Java에서는 Class 인스턴스가없는 일반 매개 변수를 얻는 방법을 잘 모르겠습니다) 실제로 관련).
… 그 정도입니다. 그래서 우리는 우리 자신의 구체적인 구현에서 타입 정보를 다시 우리 자신에게 푸시하고 그것을 사용하여 클래스 핸들에 액세스합니다. 우리는 getGenericSuperclass ()를 두 배로 늘리고 두 레벨로 가거나 getGenericSuperclass ()를 제거하고 구체적인 유형으로 가치를 얻을 수 있습니다 (캐비티 :이 시나리오를 테스트하지 않았지만 아직 나에게 오지 않았습니다).
구체적인 자녀가 홉을 임의의 수로 멀리 떨어 뜨리거나 구체적이지 않고 최종적이지 않은 경우 까다로워지고, (매우 깊은) 자녀 중 하나가 자신의 제네릭을 갖기를 기대하는 경우 특히 까다 롭습니다. 그러나 일반적으로 이러한 고려 사항을 중심으로 디자인 할 수 있으므로 대부분의 방법으로 얻을 수 있습니다.
이것이 누군가를 도왔기를 바랍니다! 이 게시물이 고대인 것 같습니다. 아마도이 설명을 잘라내어 다른 질문을 위해 보관할 것입니다.
답변
실제로 나는 이것을 작동시켰다. 다음 스 니펫을 고려하십시오.
Method m;
Type[] genericParameterTypes = m.getGenericParameterTypes();
for (int i = 0; i < genericParameterTypes.length; i++) {
if( genericParameterTypes[i] instanceof ParameterizedType ) {
Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"
}
}
jdk 1.6을 사용하고 있습니다.
답변
실제로 “익명 클래스”트릭 과 슈퍼 타입 토큰 의 아이디어를 적용하여 해결책이 있습니다 .
public final class Voodoo {
public static void chill(final List<?> aListWithSomeType) {
// Here I'd like to get the Class-Object 'SpiderMan'
System.out.println(aListWithSomeType.getClass().getGenericSuperclass());
System.out.println(((ParameterizedType) aListWithSomeType
.getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]);
}
public static void main(String... args) {
chill(new ArrayList<SpiderMan>() {});
}
}
class SpiderMan {
}
의 창조의 트릭 거짓말 익명 클래스 , new ArrayList<SpiderMan>() {}
원래 (단순)의 장소에서 new ArrayList<SpiderMan>()
. 성가신 클래스 (가능한 경우)를 사용하면 컴파일러가 SpiderMan
type 매개 변수에 지정된 형식 인수에 대한 정보를 유지합니다 List<?>
. oil!
답변
유형 삭제 때문에 목록의 유형을 아는 유일한 방법은 유형을 메소드에 매개 변수로 전달하는 것입니다.
public class Main {
public static void main(String[] args) {
doStuff(new LinkedList<String>(), String.class);
}
public static <E> void doStuff(List<E> list, Class<E> clazz) {
}
}
답변
매개 변수화 된 인터페이스의 일반 매개 변수를 가져 오는 @DerMike의 답변 부록 ( 중복을 피하기 위해 Java-8 기본 메소드 내에서 #getGenericInterfaces () 메소드 사용 ) :
import java.lang.reflect.ParameterizedType;
public class ParametrizedStuff {
@SuppressWarnings("unchecked")
interface Awesomable<T> {
default Class<T> parameterizedType() {
return (Class<T>) ((ParameterizedType)
this.getClass().getGenericInterfaces()[0])
.getActualTypeArguments()[0];
}
}
static class Beer {};
static class EstrellaGalicia implements Awesomable<Beer> {};
public static void main(String[] args) {
System.out.println("Type is: " + new EstrellaGalicia().parameterizedType());
// --> Type is: ParameterizedStuff$Beer
}
답변
아니, 그건 불가능 해 호환성 호환성 문제로 인해 Java의 제네릭은 유형 삭제 (즉 , 런타임시)를 기반으로 List
합니다. 런타임에 형식 매개 변수에 대한 정보가 있지만 개체 정의가 아니라 클래스 정의에 있습니다 (예 : ” 이 필드의 정의에서 어떤 일반 형식을 사용합니까? “).