2010-04-08 25 views
22

Câu hỏi đơn giản, cách làm cho mã này hoạt động?Cách làm việc với các biến và phản ánh

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); 
    } 
} 

Output:

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) 

Trả lời

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

công trình. Vấn đề là getMethod(..) chỉ tìm kiếm các phương pháp public. Từ javadoc:

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

Cập nhật: Sau khi nhận được thành công phương pháp này, bạn có thể gọi nó bằng cách sử:

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

đó là - tạo ra một Object mảng mới với một yếu tố - mảng String. Với tên biến của bạn nó sẽ như thế nào:

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

Cảm ơn! Nhưng bây giờ tôi bị mắc kẹt tại lời kêu gọi. – PeterMmm

+0

Cảm ơn bạn một lần nữa! Không thấy điều đó. – PeterMmm

+0

+1 cho giải pháp 'invoke'; đó là một điều khó chịu. – polygenelubricants

8

// trước khi chỉnh sửa:

Vấn đề của bạn là một thực tế rằng getMethod tìm kiếm thành viên public.

Từ (tôi nhấn mạnh) Class.getMethod:

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

Vì vậy, bạn có hai lựa chọn:

  • Hãy public void foo(String... s) và sử dụng getMethod
  • Sử dụng getDeclaredMethod thay

Lưu ý rằng sự khác biệt tương tự tồn tại r getField/s vs getDeclaredField/sgetConstructor/s vs getDeclaredConstructor/s.


// invoke vấn đề

Điều này đặc biệt khó chịu, nhưng những gì xảy ra là invoke(Object obj, Object... args) làm cho nó phức tạp nếu bạn cần phải vượt qua một loạt các loại tài liệu tham khảo như một tham số duy nhất, bởi vì nó được đúc-thể đến Object[], mặc dù nó phải được bọc bên trong một new Object[1] thay thế.

Bạn có thể làm:

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

này sẽ bỏ qua cơ chế vararg. Bạn càng có thể thực hiện ngắn gọn hơn:

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

Việc truyền tới Object làm cho cơ chế chênh lệch thực hiện công việc tạo mảng cho bạn.

Bí quyết cũng là cần thiết khi chuyển một số null làm đối số cho các biến thể và không có gì liên quan đến phản chiếu.

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

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

1, tốt đẹp cho điều này diễn viên – PeterMmm

+0

@polygenelubricants, trường hợp của tôi là: void foo() chức năng có đối số Param ... param (Gợi ý: Param là loại chung) thay vì String ... s. Tôi đã sử dụng Object mới [] {new URL ("google.com")}, nhưng nhận được lỗi sau: IllegalArgumentException: đối số 1 phải có kiểu java.lang.Object [], có java.net.URL. Cảm ơn bạn trước. – MapleLover

Các vấn đề liên quan