2011-12-22 4 views
1

리플렉션을 사용하여 주어진 클래스 이름 문자열로 클래스 객체를 인스턴스화해야하는 템플릿 메소드가 있습니다. 리턴하는 클래스가 타입 변수를 사용하는 인터페이스의 구현이기 때문에이 케이스는 약간 복잡합니다. 클래스 이름 문자열과 인터페이스의 유형 변수 유형을 전달하고 클래스 객체를 만들고 싶습니다. 경고 나 @SuppressWarnings 주석의 사용없이 자바 1.5에서이 방법을 구현하는리플렉션을 사용하여 객체를 만드는 템플릿 메소드 만들기

<T> Class<? extends Foo<T>> 
createClassObject(String className, Class<T> classTypeVariable); 

이 가능 예를 들면 다음과 같습니다 방법 서명은?

EDIT : 토마스 코멘트 덕분에 편집 방법 서명이 수정되었습니다.

+1

은''클래스 '보다는'T'의 인스턴스 classTypeVariable'하지 않나요? – Thomas

+0

Btw, 런타임에 클래스를 생성 하시겠습니까? 아니면 그냥 찾으세요? 또는 그 클래스의 인스턴스, 즉 객체를 만들고 싶습니까? – Thomas

+0

@ 토마스, Class 개체 인 Class.forName()의 반환 결과를 사용합니다. – jilt3d

답변

3

아니요, @SuppressWarnings 주석을 사용하거나 경고없이 사용할 수는 없습니다. Class.forName()이 Class로 입력되기 때문입니다. 더 구체적인 것으로 (예를 들어, 라인 Class<? extends Foo<T>>을 따라 무언가를 던지려고하면) 유형 삭제 관련 경고가 나타납니다. Class.forName(). newInstance()를 캐스팅하려고 시도하는 경우에도 마찬가지입니다.

즉,이 방법은 @SuppressWarnings을 긍정적으로 사용하는 대표적인 예라고 생각합니다. 이 경우 주석을 사용하는 데 어떤 문제도 나타나지 않습니다. 물론, Class.forName(className)Foo<T>까지 확장된다는 논리를 추가하여 주조가 올바른지 확인하는 것이 좋습니다. 이 런타임 검사는 메서드를 더 약하게 만들지 않습니다. 메서드에 Class.forName() 호출이 있으면 잠재적 런타임 유형 오류가 발생할 수 있습니다.

+1

'Class '을'Class.asSubclass()'를 사용하여 더 구체적으로 캐스트 할 수 있습니다. 예를 들어 문자열 클래스 인 경우 'Class.forName (className) .asSubclass (String.class)' . 서브 클래스 ('Foo')가 매개 변수화되어 있기 때문에이 경우에는 작동하지 않습니다. –

+0

@ 케빈 케이 : 정확하게하려고 했어요! – jilt3d

1

리턴 된 클래스가 generic (Bar<T> extends Foo<T> 또는 기타 등등)으로되어 있다면, (삭제로 인해) 유형 시스템이 런타임에 확인할 방법이 없기 때문에 가능하지 않다는 것을 확신합니다. 반환되는 Class.forName(...) 클래스는 Class<Bar<U>> 또는 이와 반대 인 Class<Bar<T>>입니다. 실제로 Bar<...> 유형을 나타내는 하나의 Class 객체가 있지만 형식 시스템에는 표현이 없으므로 Class<Bar<T>>Class<Bar<U>>은 완전히 다른 유형의 객체입니다.) 가장 가까운 객체는 무엇인가입니다. 이 같은 : 당신이 Foo<T>에 대한 충분한 정보를 가지고 있다는 생각으로 컴파일러를 속여 검사되지 않은 캐스트를 사용

<T> Class<? extends Iterable<T>> createClassObject 
     (final String className, final Class<T> clazz) throws Exception 
    { return Class.forName(className).asSubclass(getIterableTClass(clazz)); } 

@SuppressWarnings("unchecked") 
<T> Class<? extends Iterable<T>> getIterableTClass(final Class<T> clazz) 
    { return (Class<? extends Iterable<T>>)(Class<?>)Iterable.class; } 

(이 경우 Iterable<T>에서)를 asSubclass 검사를 할 수 있습니다.

그러나 반환되는 클래스가 이 아니고이 아닌 일반 (Bar extends Foo<String> 또는 그 이상)이라고 가정하면 확실하지 않습니다. 나는 그것들을 다루는 반성의 부분들에 대해서는 다루지 않았지만 그것이 존재한다는 것을 알고있다. 나는 그들이 실제로 당신이 Foo<String>을 확장하는지 결정하기 위해 Bar의 상속 계층 구조를 충분히 검사 할 수 있다고 확신하지만, 컴파일러가 당신에게 ' 그렇게 했어.

0

예. 수행 할 수 있습니다. NetBeans IDE 7에서는 아무런 경고 메시지가 표시되지 않습니다.

수정 : 죄송합니다.이 기능을 사용할 수 없으므로 클래스 구성이 없습니다. 물론 ClassLoader, 프록시 클래스 또는 ASM을 사용할 수 있습니다.

public class Bar<T> extends Foo<T> { 
} 

정말 논리적이고 간단합니다. 단서는 아마도 연결된 newInstance()를 수행하고있을 것입니다.

public <T> Class<? extends Foo<T>> createClassObject(String className, Class<T> classTypeVariable) { 
    try { 
     Class<? extends Class> resultType = Bar.class.getClass(); 
     return resultType.getConstructor(classTypeVariable).newInstance(); 
    } catch (InstantiationException ex) { 
     throw new IllegalStateException(ex); 
    } catch (IllegalAccessException ex) { 
     throw new IllegalStateException(ex); 
    } catch (IllegalArgumentException ex) { 
     throw new IllegalStateException(ex); 
    } catch (InvocationTargetException ex) { 
     throw new IllegalStateException(ex); 
    } catch (NoSuchMethodException ex) { 
     throw new IllegalStateException(ex); 
    } catch (SecurityException ex) { 
     throw new IllegalStateException(ex); 
    } 
} 
관련 문제