2009-07-14 10 views
5
내가 런타임에, 반사를 사용하여 컬렉션의 제네릭 형식을 좀하고 싶습니다

.지정 제네릭 컬렉션 형식 PARAM (자바 반사)

코드 (JAVA) :

Field collectionObject = object.getClass().getDeclaredField(
    collectionField.getName()); 
//here I compare to see if a collection 
if (Collection.class.isAssignableFrom(collectionObject.getType())) { 
    // here I have to use the generic type of the collection 
    // to see if it's from a specific type - in this case Persistable 
    if (Persistable.class.isAssignableFrom(GENERIC_TYPE_COLLECTION.class)) { 
    } 
} 

런타임에 자바 컬렉션의 일반적인 유형을 가져 오는 방법이 있나요? 제 경우에는 컬렉션의 제네릭 타입의 .class가 필요합니다.

미리 감사드립니다.

+0

나는 비슷한 문제에 직면했다. 그리고 이것은 마침내 나를 위해 그것을 해결했다 : http://stackoverflow.com/a/183232/639119 – Zds

답변

17

Type erasure은 실행시에 개체의 제네릭 형식에 대한 정보가 존재하지 않는다는 것을 의미합니다.

(링크는 가능하면 객체의 유형에 정말 관심이있어, 자바 제네릭 : 그러나

에 대해 질문을 할 수있어 거의 모든 질문에 대답해야 안젤리카 랭의 Java Generics FAQ의 관련 섹션입니다 - 필드의 유형에 관심이 있습니다. 내가 질문을 오해하고, 대답은 인정되었지만 필드 유형 매개 변수 자체를 사용하지 않는 경우 나는 그것을 할 수있는 지금 고정 :)

을하여 보상 할 수 있도록 노력하겠습니다. 예를 들어 : 필드가 필드 List<T> 인과 클래스 T에 있다면

import java.lang.reflect.*; 
import java.util.*; 

public class Test 
{ 
    public List<String> names; 

    public static void main(String [] args) 
     throws Exception // Just for simplicity! 
    { 
     Field field = Test.class.getDeclaredField("names"); 

     ParameterizedType type = (ParameterizedType) field.getGenericType(); 

     // List 
     System.out.println(type.getRawType()); 

     // Just String in this case 
     for (Type typeArgument : type.getActualTypeArguments()) 
     { 
      System.out.println(" " + typeArgument); 
     } 
    } 
} 

다음 컬렉션에 대한 형식 인수를 알기 위해 인스턴스에 대한 형식 인수를 알아야 할 것입니다. 당신의 필수 코드로이 번역

하지만 다소 까다 롭습니다 - 당신이 정말로 컬렉션 클래스의 시점에서 형식 인수를 알아야합니다.

public class StringCollection implements Collection<String> 

을 다음 유형 StringCollection의 필드 자체가 모든 유형의 인수를하지 않았을 해당 필드를했다 : 예를 들어, 누군가가 선언했다. 그런 다음 원하는 것을 찾을 때까지 getGenericSuperTypegetGenericInterfaces을 반복적으로 확인해야합니다.

정말 가능, 비록 그렇게 쉽지 않을거야. 내가 너라면 너의 디자인을 바꿔서 너가 필요 없다고 생각해.

+1

재귀 확인은 실제로 쉽지 않습니다, 고려해야 할 많은 코너 사례가 있습니다. 그리고 그것은 단지 첫 단계 일뿐입니다. 다음으로 generics를 처리하는 isAssignableFrom 동등한 것이 필요합니다. 직접 구현하려고하지 않는 것이 좋습니다. 나는 이것을 위해 gentyref라는 라이브러리를 썼다. http://code.google.com/p/gentyref/를 참조하십시오. –

0

당신은 당신이 Field.getGenericType과에서 개체를 읽어 필드의 일반적인 유형을 얻을 수 있습니다. 필드는 원시 형식이거나 희귀 유형 (generic이지만 일반적인 인수가 원시)이거나 인스턴스 유형을 사용하고 와일드 카드를 사용할 수 있습니다.

0

내 게시물에서 복사 할 때 : https://stackoverflow.com/questions/1004022/java-generic-class-determine-type/1005283#1005283

나는 그가 몇 가지 프로젝트 여기 설명 것과 유사한 솔루션을 사용하고 꽤 유용 발견했습니다.

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

그것의 JIST는 런타임에 유형 매개 변수를 결정하기 위해 다음과 같은 사용 :

public Class returnedClass { 
    ParameterizedType parameterizedType = 
    (ParameterizedType) getClass().getGenericSuperClass(); 
return (Class) parameterizedtype.getActualTypeArguments()[0]; 
} 
9

당신은 절대적으로 당신이 원하는 것을 할 수 있습니다.유형 삭제는 제네릭 유형의 컬렉션 인 인스턴스을 검사 할 수 없지만 해당 제네릭 유형의 필드를 확실히 검사 할 수 있음을 의미합니다.

class Thing { 
    List<Persistable> foo; 
} 


Field f = Thing.class.getDeclaredField("foo"); 
if(Collection.class.isAssignableFrom(f.getType()) { 
    Type t = f.getGenericType(); 
    if(t instanceof ParameterizedType) { 
    Class genericType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; 
    if(Persistable.class.isAssignableFrom(genericType)) 
     return true; 
    } 
} 

그런 다음 위의 작동하지 않습니다

Class Thing<T> { 
    List<T> foo; 
} 

이있는 경우, 예를 들어, 여기에서 잘못 갈 수있는 많은 일들이있다.

+1

나는이 줄을 추측하고있다 : Class genericType = (Class) ((ParameterizedType) t) .getActualTypeArguments [0]; 은 이어야합니다. 클래스 genericType = (클래스) ((ParameterizedType) t) .getActualTypeArguments() [0]; ? – andersonbd1