2012-02-27 3 views
1

자바 리플렉션을 사용하여 가변 arity 메소드를 호출 할 때 어떤 일이 벌어지고 있는지 이해하고 싶습니다. 이제 우리는 간단한 방법이 있다고 가정 해 봅시다 :Java 리플렉션으로 가변 방식을 호출 하시겠습니까?

void doAllTheThings(Object ... things) { 
    // ...which does something with all the things... 
} 

을 우리가 동적으로 호출 할, 그래서 우리는 반사를 통해 방법을 잡아 :

Method doItAll = Superklass.getDeclaredMethod("doAllTheThings", Object[].class); 

을 그리고 배열 전달 :

Object[] allTheThings = new Object[] { "abc", true, 15 }; 
doItAll.invoke(allTheThings); 

자, 이건 내 직감이 생각한대로 작동하지 않는 것 같습니다. 특히, 이것과 같은 varargs를 가진 메소드를 호출하려고 시도 할 때 IllegalArgumentException의 다양한 음영을 얻는 것처럼 보입니다.

여기에 분명히 누락 된 것이 있습니다. 내 생각 엔 변수가 varargs에 정렬되는 방식과 관련이있다. this four year old blog post which seems to be talking about the same issue을 찾았지만 '성공적인'사례를 재현 할 수 없습니다. 여기에 무슨 일이 일어날 지에 대한 생각은 없습니까?

Object[] allTheThings = new Object[] { "abc", true, 15 }; 
doItAll.invoke(o, new Object[]{allTheThings}); 

이유는 단일 things 파라미터 타입 Object[] 단일 파라미터로 컴파일러에 의해 변환되는 것을 및 invoke의 배열을 취

답변

8

는이 경우에 Object[][] 전달해야 매개 변수의 값.

는 명확하게하기 위해 더 많은 매개 변수를 사용하는 방법을 생각해 보면 컴파일러는 당신을위한 외부 배열을 만들 수 있도록 할 수 있습니다

void doMoreThings(Foo bar, Object ... things) { ... } 

Object[] allTheThings = new Object[] { "abc", true, 15 }; 
doMore.invoke(o, new Object[]{new Foo(), allTheThings}); 

invoke는 자체가 변수 인수를 취하도록 (듯이) 선언되고있다. 그러나 당신이 이미 그것을했다고 생각하기 때문에 당신이 Object[]를 통과한다면 이것을하지 않을 것입니다. 이미 배열이 있다는 것을 이제 더 이상 첫 번째 줄에 캐스팅, 이제 컴파일러하지 않는

doItAll.invoke(o, (Object)allTheThings); 
doMore.invoke(o, new Foo(), allTheThings); 

주, 그래서 하나를 만들어 : 그래서 그냥 컴파일러에서 그 사실을 숨 깁니다. 컴파일러는 어쨌든 다른 기회가 없으므로 두 번째 줄에서는 이것이 필요하지 않습니다.

편집 : 참고가 invokedoAllTheThings 방법 클래스의 인스턴스를 전달 놓친 때문에 코드도 컴파일되지 않습니다 (난 내 코드에서 o을 이름).

+0

응답과 특히 편집에 대해 감사드립니다. (편집 한 내용에서 발견 한 감독 기능으로 인해 예제 코드를 얻을 수없는 이유가 설명됩니다!) –

관련 문제