2014-02-25 2 views
1

Type 인스턴스 (Class 또는 ParameterizedType 일 수 있음)가 주어지면 클래스에서 구현 된 특정 유형의 인터페이스를 가져와야합니다. generics가 없다면 이것은 쉽습니다. Class 인스턴스에서 getInterfaces()를 호출하면 완료됩니다. 그러나 구현 된 인터페이스에 원래 클래스의 유형 매개 변수 자체에 종속되거나 종속되지 않는 자체 유형 매개 변수가있는 경우에도이 기능이 필요합니다. 클래스 유형 매개 변수가 적용된 구현 인터페이스의 유형 인스턴스 가져 오기

class Foo implements Iterable<Integer> {} 

에게 주어진뿐만 아니라 클래스에게 주어진 Iterable을 < 문자열 >을 반환해야 할 때

예로, 함수의 Iterable < 정수 >를 반환해야

class Bar<T> implements Iterable<T> {} 

과 바 <을 나타내는 ParmeterizedType 문자열 >

내장 된 리플렉션, 타사 도구 등으로 쉽게이 작업을 수행 할 수 있습니까?

명확히하려면 리터럴 (Foo.class 등)을 통해 검색된 유형 인스턴스뿐만 아니라 적용된 유형 매개 변수를 포함 할 수있는 리플렉션을 통해 반환 된 유형 (예 : 메소드에서 리플렉션을 통해 반환 된 리턴 유형)도 작동해야합니다.

static Bar<String> magic() { ... } 

이것은 원시 Bar 클래스 및 String 유형 인수를 참조하는 ParameterizedType입니다.

답변

2

를 사용하는 예입니다 Google Guava TypeToken 클래스 : http://code.google.com/p/guava-libraries/wiki/ReflectionExplained

다양한 유형의 유형을 해결하기위한 정교한 메커니즘을 제공합니다.그리고 내가 제대로 질문을 이해 경우 는 다음 TypeToken#resolveType(Type) 방법 같은 것을 당신이 찾고있는 무엇에 가까운 수 있습니다 :

import java.lang.reflect.Method; 
import java.lang.reflect.Type; 
import java.util.Iterator; 

import com.google.common.reflect.TypeToken; 

class Foo implements Iterable<Integer> { 

    @Override 
    public Iterator<Integer> iterator() 
    { 
     return null; 
    } 
} 

class Bar<T> implements Iterable<T> { 

    @Override 
    public Iterator<T> iterator() 
    { 
     return null; 
    } 
} 

public class TypeParameterTest 
{ 
    public static void main(String[] args) throws Exception 
    { 
     Type i0 = getInterface(Foo.class, 0); 
     System.out.println("First interface implemented by Foo: "+i0); 

     Method method = TypeParameterTest.class.getDeclaredMethod("magic"); 
     Type returnType = method.getGenericReturnType(); 

     System.out.println("Magic method return type: "+returnType); 

     Type i1 = getInterface(returnType, 0); 
     System.out.println("First interface implemented by Bar<String>: "+i1); 
    } 

    private static Type getInterface(Type type, int interfaceIndex) 
    { 
     TypeToken<?> typeToken = TypeToken.of(type); 
     Class<?> c = typeToken.getRawType(); 
     Type[] interfaces = c.getGenericInterfaces(); 
     if (interfaces.length == 0) 
     { 
      return null; 
     } 
     Type i = interfaces[interfaceIndex]; 
     return typeToken.resolveType(i).getType(); 
    } 

    public static Bar<String> magic() { return null; } 
} 

출력은 여기 이것은 단순히 사실이 아니다

First interface implemented by Foo: java.lang.Iterable<java.lang.Integer> 
Magic method return type: Bar<java.lang.String> 
First interface implemented by Bar<String>: java.lang.Iterable<java.lang.String> 
+0

나는 그것이 내가 필요한 바로 그 것이라고 생각한다. 만약 내가 할 수있는 최대 10 표를 줄 것입니다 :) – SoftMemes

0

유형이 하드 코딩 된 경우 반사를 사용할 수 있습니다. 특정 유형을 하위 클래스로 지정하기 때문입니다. 여기서 유형은 클래스 정보에 저장됩니다.

당신이 반사를 사용하는 경우 FooIterable<String>를 확장하지만 당신은 Bar<String>있는 경우이 때문에 형의 삭제에 불과 런타임에 Bar이며, 당신이 보는 모두가 당신이있는 경우 BarIterable<T>

을 확장하는 것을 볼 수 있습니다 매개 변수화 된 제네릭 형식은 런타임에 아무런 작업도 수행하지 않으므로 아무데도 기록되지 않습니다. 이 유형이 필요한 경우 추가 필드로 저장해야합니다.

이 런타임에 유형을 확인하는 수준의 Collections.CheckedMap이고 그 다음이

private static class CheckedMap<K,V> 
    implements Map<K,V>, Serializable 
{ 
    private static final long serialVersionUID = 5742860141034234728L; 

    private final Map<K, V> m; 
    final Class<K> keyType; 
    final Class<V> valueType; 
+0

입니다. 리플렉션을 사용하여 적용된 형식 매개 변수를 포함하여 완전한 형식을 포함 할 메서드의 반환 형식을 ParameterizedType 형식으로 읽습니다. – SoftMemes

+0

@SoftMemes 런타임에 작성되는 유형이 아닌 클래스 정보로만 구울 수있는 유형을 읽을 수 있습니다. –

+0

피터 (Peter)는 권장 사항이 아니므로 가능한 것은 그렇다고 생각합니다. 일반적인 인수와 메소드 인수를 전달할 때의 차이점은 무엇입니까? –

0

처럼 시작하면 아마 한 번 봐 가지고 있어야하는 ParameterizedType

import java.lang.reflect.*; 

public class Foo { 

    static class Bar<T> { 

    } 
    static class SubBar extends Bar<Integer> { 

    } 

    public static void main(String argv[]) { 

    ParameterizedType pt = (ParameterizedType)SubBar.class.getGenericSuperclass(); 
    Type[] t = pt.getActualTypeArguments(); 

    for (int i=0;i<t.length;i++) { 

     System.out.println(t[i]); 
    } 
    } 
} 
+0

두 가지 문제가 있습니다. 우선 그것은 인터페이스보다는 기본 클래스를 사용합니다. 제 경우에는 인터페이스가 필요합니다. 둘째, SubBar에 전달 된 유형 매개 변수 (잠재적으로 다른 유형 내부)가있을 때 정답을주지 못합니다. – SoftMemes

+0

유형 [] genericInterfaces = BarFoo.class.getGenericInterfaces(); (유형 genericInterface : genericInterfaces) { if (genericInterface instanceof ParameterizedType) { 유형 [] genericTypes = ((ParameterizedType) genericInterface) .getActualTypeArguments(); (유형 genericType : genericTypes) { System.out.println ("일반 유형 :"+ genericType); } } –

+0

형식 매개 변수가 전달되는 경우 실제로 적용되지 않습니다. 이것은 미해결 TypeVariable로 끝날 것입니다. – SoftMemes

0
import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.Iterator; 

public class Dummy implements Iterable<Integer> { 

    public static void main(String args[]) throws Exception { 

     Dummy d = new Dummy(); 

     Type[] genericInterfaces = Dummy.class.getGenericInterfaces(); 

     for (Type genericInterface : genericInterfaces) { 
      if (genericInterface instanceof ParameterizedType) { 
       Type[] genericTypes = ((ParameterizedType) genericInterface).getActualTypeArguments(); 

       for (Type genericType : genericTypes) { 

        System.out.println("Generic type: " + genericType); 
       } 
      } 
    } 
    } 

    @Override 
    public Iterator<Integer> iterator() { 
     // TODO Auto-generated method stub 
     return null; 
    } 

} 
+0

이제 위 예제에서 선언 한대로 Bar 을 반환하는 메서드에서 리플렉션을 통해 반환 된 Type에서 시도해보십시오. – SoftMemes

관련 문제