2010-04-08 6 views
22

Basit bir soru, bu kodu nasıl çalışıyor?Varargs ve yansıma ile çalışma nasıl

public class T { 

    public static void main(String[] args) throws Exception { 
     new T().m(); 
    } 

    public // as mentioned by Bozho 
    void foo(String... s) { 
     System.err.println(s[0]); 
    } 

    void m() throws Exception { 
     String[] a = new String[]{"hello", "kitty"}; 
     System.err.println(a.getClass()); 
     Method m = getClass().getMethod("foo", a.getClass()); 
     m.invoke(this, (Object[]) a); 
    } 
} 

Çıktı:

class [Ljava.lang.String; 
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 

cevap

41
Test.class.getDeclaredMethod("foo", String[].class); 

çalışır. Sorun, getMethod(..)'un yalnızca public yöntemlerini araştırmasıdır.

Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object.

Güncelleme: başarıyla yöntemi aldıktan sonra, kullanarak çağırabilirsiniz: javadoc itibaren

m.invoke(this, new Object[] {new String[] {"a", "s", "d"}}); 

olduğunu - String dizi - bir eleman ile yeni Object dizi oluşturun. Değişken isimlerinde sayesinde olmazdı gibi:

m.invoke(this, new Object[] {a}); 
+0

Teşekkürler! Ama şimdi davete bağlı kaldım. – PeterMmm

+0

Tekrar teşekkürler! Bunu görmedim. 'Invoke' çözümü için – PeterMmm

+0

+1; Bu iğrenç bir şey. – polygenelubricants

8

// düzenlemek için önce:

Senin sorunun getMethod bir public üyesi arar olması. Class.getMethod (vurgu mayın) Gönderen

:

Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object

Yani iki seçenek vardır:

  • public void foo(String... s) yapın ve getMethod
  • kullanın yerine

Not getDeclaredMethod kullandığını aynı fark var vs getDeclaredField/s ve getConstructor/s vs getDeclaredConstructor/s numaralı telefonlardan getField/s numaralı telefonu kullanabilirsiniz.


// invoke sorun

Bu özellikle pis, ama dökme mümkün olduğu için ne olur, bir tek argüman olarak referans türü bir dizi geçmesi gerekiyorsa invoke(Object obj, Object... args) çok çetrefilli hale olmasıdır Bunun yerine new Object[1] içine sarılması gerekmesine rağmen Object[].

Sen yapabilirsiniz:

m.invoke(this, new Object[] {a}); // Bohzo's solution 

Bu vararg mekanizmasını atlar. Daha özlü da yapabilirsiniz:

m.invoke(this, (Object) a); 

Object için dökme vararg mekanizması sizin için diziyi yaratma işi yapar.

Aynı zamanda varargs için bir argüman olarak bir null geçirirken de gerekli ve yansıma ile ilgisi yoktur.

public void foo(String... ss) { 
    System.out.println(ss[0]); 
} 

    foo(null); // causes NullPointerException 
    foo((String) null); // prints "null" 
+1

+1, – PeterMmm

+0

@polygenelubricants, bu durumda benim durumum: void foo() fonksiyon argüman Param ... param (İpucu: Param genel tip) String ... s. Yeni Nesne [] {new URL ("google.com")} kullandım, ancak şu hatayı aldım: IllegalArgumentException: argüman 1 java.lang.Object [] türünde olmalı, java.net.URL adresini aldım. Şimdiden teşekkür ederim. – MapleLover