2012-12-08 27 views
11

Trong Java, bạn có thể ghi đè lên các phương thức trong lớp mà bạn tạo bằng cách sử dụng reflection không? Ví dụ, nói rằng tôi có lớp sau:Làm thế nào tôi có thể ghi đè lên các phương thức trong Java khi tôi tạo một đối tượng thông qua sự phản chiếu?

public class MyObject 
{ 
    public String foo, bar; 

    public MyObject(String foo) 
    { 
     this.foo = foo; 
     this.bar = foo + "bar"; 
    } 

    public void setBar(String bar) 
    { 
     this.bar = bar; 
    } 
} 

Và trong một lớp Tôi muốn tạo nó trực tiếp và ghi đè phương pháp setBar của nó như sau:

MyObject obj = new MyObject("something") 
{ 
    @Override 
    public void setBar(String bar) 
    { 
     this.bar = this.foo; 
    } 
}; 

Có cách nào để ghi đè lên một phương pháp theo cách tương tự này bằng cách sử dụng sự phản chiếu? Có thể một cái gì đó như thế này? :

Class<?> _class = Class.forName("com.example.MyObject"); 
Constructor<?> _constructor = _class.getConstructor(new Class<?>[]{String.class}); 
Method m = _class.getMethod("setBar", new Class<?>[]{String.class}); 
Object obj = _constructor.newInstance("Foo String") 
{ 
    m = new Method(new Class<?>[]{String.class}) 
    { 
     System.out.println("Foobar"); 
    } 
}; 

Nếu không, có cách nào khác để thực hiện việc này hoặc thư viện bên ngoài có thể trợ giúp không? Tôi đang tìm cách để thêm người nghe vào một phương thức setter để thay đổi các giá trị liên kết.

+1

Bạn cần thư viện tạo mã động, chẳng hạn như * javassist *. –

Trả lời

10

Không, không thể thực hiện được ví dụ của bạn.

Trong ví dụ của bạn, trình biên dịch Java sẽ tạo ra hai lớp riêng biệt:

MyObject.class 
MyObject$1.class 

Sau đó là một phương pháp ghi đè. Trong trường hợp này, đó là lớp bên trong ẩn danh (Xem Java tutorial documentation)

Nhưng có nhiều giải pháp phức tạp hơn liên quan đến thư viện dệt bytecode. Các thư viện như cglib, asm, javassist vv cung cấp cho bạn một cơ sở để tự động tạo các lớp mới trong thời gian chạy và tải chúng.

Javassist có hướng dẫn về cách add methods to classes at runtime. Bạn có thể điều chỉnh nó để thêm/ghi đè phương thức, như sau:

CtClass origClazz = ClassPool.getDefault().get("org.example.MyObject"); 
CtClass subClass = ClassPool.getDefault().makeClass(cls.getName() + "New", origClazz); 
CtMethod m = CtNewMethod.make(
      "public void setBar(String bar) { this.bar = bar; }", 
      subClass); 
subClass .addMethod(m); 
Class clazz = cc.toClass(); 
+0

Đây gần như chính xác những gì tôi đang tìm kiếm - nhưng tôi chắc chắn có thể phù hợp với nó. – Phil

0

Không, những gì bạn đang yêu cầu là một cái gì đó như biên soạn thời gian chạy. Mặc dù không phải là không thể, nhưng chắc chắn nó không phải là thứ mà API phản chiếu cung cấp.

2

Nếu bạn đang trả về một đối tượng thuộc loại giao diện, bạn có thể sử dụng Proxy.newProxyInstance để nhận một thể hiện của giao diện tự động gửi lời gọi phương thức đến đối tượng InvocationHandler.

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