2011-05-06 6 views
3

을 방지 할 수 있습니다.결합 자바 제네릭 및 반사 내가이 같은 일부 코드가 캐스팅

Method m = MyClass.class.getMethod("myMethod", String.class); 
String result = (String)doMethod(m, "Hello"); 

이 나를 위해 (인수 및 모든 변수 수) 잘 작동합니다 : doMethod를 호출하려면이 같은 뭔가. 나를 괴롭히는 것은 호출자의 String에게 필요한 캐스트입니다.myMethodString을 반환한다고 선언 했으므로 doMethod은 반환 유형을 String으로 변경할만큼 현명해야합니다. Java generics를 사용하여 이와 같은 작업을 수행 할 수있는 방법이 있습니까? 이 루틴 자체 캐스트를 이동하지만

String result = doMethod(m, "Hello"); 
int result2 = doMethod(m2, "other", "args"); 

답변

4

,

@SuppressWarnings("unchecked") 
<T> T doMethod(Method m, Class<T> returnType, Object Args ...) { 
    Object obj = m.getDeclaringClass().getConstructor().newInstance(); 
    return (T) m.invoke(obj, args); 
} 

String result = doMethod(m, m.getReturnType(), "Hello"); 

하나는 수행 할 그런 일을 요구 아키텍처에 대한 안일 호기심,하지만 당신은 당신 것이 마음에 들지 않으면 그 범위 :

에서 잘입니다 또한 returnType의 바인딩을 무시할 수 있으며 컴파일러는 반환 유형을 할당 할 대상에 자동으로 캐스트합니다. 예를 들어, 이는 합법적입니다.

@SuppressWarnings("unchecked") 
<T> T doMethod(Method m, Object Args ...) { 
    Object obj = m.getDeclaringClass().getConstructor().newInstance(); 
    return (T) m.invoke(obj, args); 
} 

캐스팅은 사용자가 할당하려고 시도하는 것이지만, 대부분의 사람들은 의심되는 것으로 생각합니다.

+1

은 안전하지 않게하기 위해 체크되지 않은 캐스트 대신 returnType.cast (...)를 사용하십시오. – mihi

+0

+1 두 번째 예는 다소 기분이 좋지만 흥미 롭습니다. Java 유추 목록에 형식 유추를 추가하고 있습니다. –

+0

그건 컴파일 시간이 안전하지 않습니다, 그것은 단지 컴파일러 경고를 숨 깁니다. 메소드의 리턴 유형이 전달한 것과 일치하지 않으면 런타임시 ClassCastException을 발생시킵니다. – Affe

1

당신은

public <T> T doMethod(Method m, Class<T> clazz, Object... args); 

을 시도 할 수 있습니다. 일반적으로 당신이하려는 것은 좋은 습관처럼 들리지 않습니다. 리플렉션 자체는 약간의 성능 오버 헤드가 발생하지만, 걱정하지 않아도 될까요? 물론

+0

이유는 메서드 호출 주위에 일부 상용구를 래핑하는 것이 었습니다. 성능 오버 헤드의 중대성에 대한 다양한 견해가있는 것 같습니다. 나는 많은 코드 재사용을 위해 약간의 성능을 희생하려하지만, 성능이 떨어지는 것은 용납 될 수 없다는 것을 알 수있다. 첫 번째 예제에서 –

3

반환 형식을 캡처하기 위해 메서드가 매개 변수화 되었으면 좋겠습니다. 당신이 공장을 가질 수 있습니다 - 당신은

public class MethodEx<T> { 
    private final Method _method; 
    private final Class<T> _returnType; 

    public MethodEx(Method method, Class<T> returnType) { 
    _method = method; 
    _returnType = returnType; 
    } 

    public T invoke(Object object, Object... args) throws InvocationTargetException { 
    try { 
     return _returnType.cast(_method.invoke(object, args)); 
    } 
    // good opportunity to hide/wrap other exceptions if your 
    // usecases don't really encounter them 
    } 
} 

이 단지 출발점이 될 것입니다 ... 그렇게 당신도 꽤 좋은 외관을 제공 할 수 있도록 할 ... 자신의 MethodEx과 방법을 포장하여 자신을 그렇게 항상 수 메서드가 public인지 확인하기 위해 많은 사전 검사를하는 MethodEx의 메서드.

마지막으로 Method 인스턴스를 캐싱하고 동적으로로드 된 클래스를 처리하는 경우이 메서드를 사용하면 메소드 및 리턴 유형에 대해 약한 참조를 방어 적으로 도입하므로 코드 전체에서 전체 클래스 로더를 조심할 필요가 없습니다.

+0

+1이 접근법은 매우 미묘하지만, 여기에서도 반환 유형을 생성자에 명시 적으로 전달해야합니다. –

+0

@Dan 당신 말이 맞습니다.하지만 그 추악함을 숨기는 팩토리 메서드를 작성할 수도 있습니다. 그러나 결국에는 컴파일 타임에 계속 전달할 수 없습니다. 리플렉션을 통해 호출되는 반환 유형이 무엇인지 항상 알 수는 없으므로 속임수를 사용하지 않아도 완전히 유형을 검사 할 수 있습니다. 논의 된 모든 접근법은 점검되지 않은 경고가 억제되어야하는 장소의 수를 줄이는 데 도움이됩니다. –