2013-08-27 2 views
48

문제 요약 : 형식 매개 변수 (예 : ArrayList<SomeClass>)가있는 클래스를 형식 매개 변수로 일반 메서드에 전달하고 싶습니다. .Java의 제네릭 메서드에 대한 형식 매개 변수로 형식 매개 변수로 전달하는 클래스

의 내가 방법을 가지고 있다고 가정 해 봅시다 :

public static <T> T getGenericObjectFromJson(String json, Class<T> genericType){ 
     // details unimportant, basically returns an object of specified type 
     return JsonParser.fromJson(json, genericType); 
    } 

이 방법은 물론, 클래스의 모든 종류의 완벽하게 잘 작동합니다. 나는 예를 들어,과 같이 메소드를 호출 할 수 있습니다

getGenericObjectFromJson(jsonString, User.class) 

문제 :는 내가이 작업을 수행 할 수 없습니다 발견 :

getGenericObjectFromJson(jsonString, ArrayList<User>.class) 

구문 적이 분명히 유효하지 않습니다. 그러나, 나는 이런 식으로 어떻게 성취 할 것인가를 확신하지 못한다. 물론 ArrayList.class을 전달할 수 있지만 제네릭 형식을 추가하면 더 이상 구문 론적으로 유효하지 않으며 그 주위를 생각할 수 없습니다.

유일한 직접 솔루션 (오히려 바보 같다) 이런 일을하고있다 :

getGenericObjectFromJson(jsonString, new ArrayList<User>().getClass()) 

그러나 우리는 어쨌든 제네릭 형식을 잃고 결국, 단순히 다시 알 수없는 유형의 ArrayList를을 (그것은 할 수 있지만 얻을 던지다). 게다가 불필요하게 객체를 인스턴스화합니다.

내 유일한 해결책은 지금까지과 같이, 인스턴스화 할 수있는 일반적인 형식 매개 변수가 포함 된 클래스에서 그 방법을 포장하고있다 :이 경우

public class JsonDeserializer<T>... 

을의 getGenericObjectFromJson 방법은 클래스의 사용 제네릭 유형.

질문 : 궁금한 점은 궁금한 점은 왜 형식 매개 변수를 사용하여 클래스를 전달할 수 없는지와 내가 시도한 것을 성취 할 수있는 방법이 있는지 궁금합니다.

언제나이 질문에 문제가 있는지 알려 주시기 바랍니다.

+7

유형 삭제로 인해 가능하지 않다고 생각합니다. Java 제네릭은 컴파일 타임 구조이며 런타임에는 존재하지 않으므로 생성 된 제네릭 형식을 나타내는'Class' 객체는 없습니다. – cdhowie

+3

해결책 :'C#', 농담하지 마라. 컴파일 할 때 java가 수행하는 "type erasure"로 인해 일반 유형 정보를 제거 할 수 없습니다. –

+1

이것을'getGenericArrayListFromJson (jsonString, User.class)'로 재 작성하려고합니까? 이것은 아마도 당신이 할 수있는 최선의 방법 일 것입니다. –

답변

55

실제로 "트릭"을 사용하여 Java에서 가능합니다. C# 광신자들의 압력에 굴복하지 마십시오! (J/K)

은 "트릭"일반적인 유형을 확장하는 클래스를 만들고 .getGenericSuperclass() 또는 .getGenericInterfaces() 의해 반환 Type 통해 상위 클래스의 유형 파라미터의 값에 액세스 할 수있다.

이것은 상당히 번거 롭습니다. 우리의 삶을 단순화하기 위해 Google은 이미 우리를 위해 코드의 지루한 부분을 대부분 작성하여 구아바를 통해 제공했습니다.

정확하게 원하는대로하는 TypeToken 클래스를 확인하십시오. 예를 들어 :

TypeToken<List<String>> stringListTok = new TypeToken<List<String>>() {}; 

은 그럼 당신은 대신 Class<T>TypeToken<T> 주위에 통과 그게 다야. 그것은 T가 나타내는 타입에 대해 반성하는 메소드를 제공합니다.

이 내부적으로하고있다 단순히 .getClass().getGenericSuperclass() (또는 ...Interfaces())를 호출 무엇, 다음 Type에서 ParameterizedType과 거기에서 모든 정보 (.getActualTypeArguments() 등) 검색 못생긴 캐스트.

마지막으로, Dependency Injection과 비슷한 작업을 수행하려는 경우 (예 : 클래스의 생성자에 Class<T>을 삽입해야한다고 가정하거나 인스턴스가 필요한 일부 매개 변수화 된 인터페이스의 인스턴스를 가져 오려고한다고 가정하십시오. 형식 매개 변수에 따라 다름) Google Guice (Google의 DI 컨테이너)는 TypeLiteral이라는 문제를 해결하는 메커니즘과 매우 유사합니다. 배후의 사용 및 코드는 Guava의 TypeToken과 거의 동일합니다. 여기에서 확인하십시오 : TypeLiteral

+1

와우, 정말 대단합니다. 재미있는 점은 실제로 구슨 (Gava)의 라이브러리를 사용하고 있습니다.이 라이브러리는 구아바 (Guava)를 사용합니다.하지만 분명히 TypeToken의 작동 방식을 완전히 이해하지 못했습니다. 매우 유용한 정보를 제공해 주셔서 감사합니다. –

+0

첫 번째 방법으로 더 자세히 설명 할 수 있습니까? AFAIK, 당신은 자바에서 제네릭 형식을 확장 할 수 없습니다. – Kedarnath

+0

@Kedarnath,'class A {} 클래스 B는 A를 확장합니다. {}'-> 이것은 절대적으로 좋습니다. 너 무슨 소리 야? 당신은 가능하지 않다고 주장하는 것에 대한 예를 제시 할 수 있습니까? –

관련 문제