2010-06-07 7 views
8

이것은 바보 같은 질문 일 수 있습니다. 그러나 방금 how to create a Type variable for a generic type을 묻는 질문을 보았습니다. 합의는 여러분이 그 타입을 반환하는 더미 메소드를 가져야하고, 리플렉션을 사용하여 그것을 얻는 것 같았다. (이 경우 그는 Map<String, String>을 원했다.) 이런 식으로 뭔가 :익명 클래스를 사용하여 매개 변수화 된 형식 개체 만들기

public Map<String, String> dummy() { throw new Error(); } 

Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType(); 

내 질문입니다, 많이, 당신은 단지 같은 것을 할 수 없음을 사용하는 반사를 가지고 있지 :

Type mapStringString = new ParameterizedType() { 
    public Type getRawType() { 
     return Map.class; 
    } 

    public Type getOwnerType() { 
     return null; 
    } 

    public Type[] getActualTypeArguments() { 
     return new Type[] { String.class, String.class }; 
    } 
}; 

겠습니까이 일을? 그렇지 않다면 왜 안 되겠습니까? 그리고 그것은 분명히 가능하지 않은 Integer<String> 같은 몇 가지 유형을 반환 할 수있는 외에 (않는 경우 위험의 일부/문제가 무엇인가.

+0

나는 제안 된 솔루션이 허용하는 것을 시도하고 있습니다 : 원시로부터 매개 변수화 된 유형 가져 오기 컴파일시에 제공되는 Type 파라미터의 타입과리스트 이 일을하는 또 다른 방법을 찾았습니까? – user48956

답변

6

당신이 수 있고, 대부분의 응용 프로그램에 아마 충분할 것이다 물론.

그러나 첫 번째 방법을 사용하면보다 세련된 개체를 얻을 수 있습니다. 예를 들어 첫 번째 방법을 사용하여 type1 개체를 만들고 두 번째 방법을 사용하여 type2 개체를 만든 다음 type1.equals(type2)은 첫 번째 메서드가 equals-method를 올바르게 구현하지만) type2.equals(type1)은 false를 반환합니다 (두 번째 방법에서는 equals-method를 재정의하지 않았으므로 0에서 구현 됨).).

동일한 추론은 toString, hashCode 등과 같은 다른 (때로는 유용한 방법들)에도 적용됩니다. 두 번째 방법은 이것들의 유용한 구현을 제공하지 않습니다.

+0

실제로 type1 (sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl) equals의 구현은 ParameterizedType에 equals 매개 변수를 캐스팅 한 다음 인터페이스 메서드를 사용하여 클래스를 비교하므로 'type1.equals (type2)'는 true를 반환하고, 반대 ('type2.equals (type1)')는 false를 반환합니다. 당신은 그것들을 구현할 수도 있지만, 코드는 약간 엉망이 될 것입니다. –

+0

물론입니다. 방법 1 에서처럼 방법 2에서 동일한 결과를 얻을 수 있지만 눈치 챘 듯이 더 많은 작업이 필요합니다. – aioobe

2

사실,이 작업을 수행하는 가장 간단한 방법 (== 최소 코드)은 관심있는 유형을 확장하는 더미 인터페이스가 될 것이라고 생각하고 클래스에서 getGenericInterfaces()[0] (사용 하시려면 getGenericSuperclass()을 사용하십시오) :

private interface MapStringString extends Map<String, String> {} 
private static ParameterizedType mapStringString(){ 
    return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0]; 
} 

그것은 당신이 표현하고 싶은 모든 ParameterizedType에 대한 새로운 클래스를 만들 필요로하지만, 확장 성 doen't. 구현이 어째서 (어딘가에 캐스트를 축소하지 않는 한) 왜 그렇게되지 않을지, 그리고 재사용 할 수있는 매력적인 이점이 있습니다.

+0

이것이 내가 처음으로 제공 한 방법으로 'hackish'한 것처럼 보이지만, 적어도 클래스를 가져 오는 대신 함수를 호출 한 다음 메서드를 얻은 다음 일반 반환 형식을 각각 가져 오는 대신 형식을 얻으려는 경우 더 나은 코드를 제공합니다. 사용하려는 시간). –

5

Google Guava 라이브러리를 프로젝트에 포함하는 경우 (위대함) 입력란을 얻기 위해 TypeToken을 사용하십시오. Google의 Gson 라이브러리 (JSON과 상호 작용하기 위해)는 version과 비슷합니다. 당신이 제 3 자 라이브러리를 사용하지 않으려면, 당신은 여전히 ​​일반적인 콘크리트 유형을 얻기 위해 익명 형식을 사용할 수 있습니다

Type t = new TypeToken<List<String>>(){}.getType(); 

: 모두가 TypeList<String>을 나타내는 얻을이 (같이 사용된다 . 코드 (이 기술은 인터페이스가 작동하지 않습니다 그것은 추상 유형에 대한 가치보다 더 문제가 될 수 있음)의 한 줄이 TypeHashMap<String, String>를 나타내는이 이렇게 얻으려면 :

Type t = new HashMap<String, String>(){}.getClass().getGenericSuperclass(); 

나는를 결과 것을 확인했다 0 인스턴스 .equals()TypeToken으로 생성 된 Type 인스턴스는 Guava의 버전 TypeToken에 대해 동일하게 검증되지 않았지만 현재로서는 액세스 할 수 없습니다.(구아바는 모든 종류의 것들에 매우 편리한 더 일반용 라이브러리입니다. 어쨌든 사용하고 있어야합니다.)

+0

이 경우에도 컴파일시 List 을 알고 있어야합니다. OP에서 원시 유형 및 매개 변수 유형은 컴파일 유형까지 알 수 없었습니다. – user48956

관련 문제