2012-04-06 42 views
7

Tôi có khả năng mở rộng một lớp tại thời gian biên dịch, nhưng tôi cần để có thể tạo một thể hiện của lớp con này khi chạy bằng cách sử dụng một cá thể của lớp cha đã được khởi tạo.Java: Mở rộng lớp lúc chạy

Điều này có thể được lý thuyết bởi vì các hàm tạo lớp bậc trên đã được gọi trước hàm tạo lớp con.

Tôi không có quyền truy cập vào chương trình đủ để thay đổi việc khởi tạo thành lớp con của tôi cũng như không làm gián đoạn quá trình khởi tạo gốc.

Trường hợp sử dụng: Có một mảng hiện tại của lớp X. Mã của tôi được tải sau. Tôi cần phải ghi đè lên một trong các phương thức của một trong các cá thể X với lớp con Y được mở rộng của tôi mở rộng X. Chương trình cha truy cập các đối tượng chỉ qua mảng đó, vì vậy tôi muốn thay thế phần tử mảng đó bằng cá thể Y của mình, nhưng nó cần cư xử như thể nó được khởi tạo ban đầu vào mảng đó. Tôi không thể chỉ kèm theo trường hợp siêu lớp và các cuộc gọi chuyển tiếp, và có những biến chứng khó khăn với việc phục hồi lại lớp cha.

Tôi hy vọng điều đó rõ ràng hơn.

+3

Vui lòng lặp lại câu hỏi. –

+1

Bạn cũng có thể cung cấp ví dụ về những gì bạn đang thực sự cố gắng thực hiện không? Thay vì chỉ mong muốn, nhưng có thể là không thể, phương pháp làm như vậy. – millimoose

+0

Giả sử dòng hiện tại "public static Foo foo = new Foo();" mà tôi không thể thay đổi. Tôi có "public class Bar mở rộng Foo" và tôi muốn làm "foo = new Bar (...)" sao cho nó giống như dòng đầu tiên là "public static Foo foo = new Bar()". – JAKJ

Trả lời

5

Để nhắc lại những gì bạn đang cố gắng làm ..

Trong JVM, có một phiên bản của ClassA. Bạn muốn tự động sửa đổi lớp heiarchy của ClassA, sao cho một lớp mới tồn tại được gọi là ClassB có nguồn gốc từ ClassA. Sau đó, bạn muốn khởi tạo một thể hiện của ClassB nhưng thực hiện lớp con của nó là của cá thể hiện tại của ClassA. Một cái gì đó giống như một sự thay thế bộ nhớ.

Bạn có thể muốn xem xét http://www.jboss.org/javassist. Những gì bạn cần làm là thay thế ClassLoader, sau đó xác định khi ClassA đang được nạp, sau đó được khởi tạo. Sau đó, bạn cần phải xây dựng ClassB và trả về thay vào đó.

Cập nhật

Sau một chút nghiên cứu nhiều hơn vẫn là khả năng bạn có thể làm những gì bạn muốn. IDE giống như Eclipse hỗ trợ triển khai phương thức HotSwap'ing trong khi gỡ lỗi. Họ sử dụng API Instrumentation.

http://zeroturnaround.com/blog/reloading_java_classes_401_hotswap_jrebel/

Bạn có thể thay thế các cơ quan phương pháp nhưng không thêm hoặc loại bỏ các phương pháp tự. Vì vậy, mặc dù bạn sẽ không thể thay đổi loại thành loại mới của mình, bạn hoàn toàn có thể thay thế triển khai phương thức bằng triển khai mới của mình.

+0

Tôi không thay đổi kế thừa khi chạy, nhưng chỉ tạo một lớp con khi lớp cha của nó đã được khởi tạo. – JAKJ

+0

@JAKJ Câu trả lời vẫn như cũ. Bạn có một đối tượng hiện có mà bạn muốn thích ứng với một loại đối tượng khác. NẾU bạn có thể kiểm soát điểm trả lại ban đầu của đối tượng mới này thì bạn có thể điều chỉnh nó và trả về cá thể bạn muốn. Tôi khuyên bạn nên cập nhật câu hỏi của mình với Trường hợp sử dụng chứ không phải những gì bạn nghĩ là giải pháp. –

+0

Tôi không có khả năng thay thế trình nạp lớp vì lớp của tôi được tải sau siêu lớp hoặc tôi không thể sử dụng thời gian chạy của bên thứ ba. Điều này phải nằm trong Java. – JAKJ

1

Bạn đã xem Java Proxies chưa?

Dưới đây là một đoạn trích từ Javadoc:

"Một lớp proxy động (gọi đơn giản là một lớp proxy dưới đây) là một lớp mà thực hiện một danh sách các giao diện quy định tại thời gian chạy khi lớp được tạo ra"

+0

Dường như proxy là giao diện chứ không phải các lớp. – JAKJ

3

tôi sẽ đề nghị sử dụng cglib:

cglib là một mạnh mẽ, hiệu suất cao và chất lượng Code Generation Thư viện, Nó được sử dụng để mở rộng các lớp học JAVA và thực hiện các giao diện khi chạy

Bạn có thể tìm thấy một số ví dụ tại đây: https://github.com/cglib/cglib/wiki

2

Tôi không biết đó có phải là một sự sollution nhưng nếu bạn có

public static Foo foo = new Foo(); 

và bạn muốn thay thế nó với Bar kéo dài Foo làm cho Bar một Wrapper cho của Foo và sử dụng phản ánh để cho điểm foo để dụ Bar của bạn.

public class Foo extends Bar { 
    private bar; 
    public Foo(Bar oldInstance) { 
    this.bar = oldInstance; 
    } 
} 

// exception handling ommitted 
public static void onStartup() { 
    Class fooRefClass = FooRef.class; 
    Field fooRef = fooRefClass.getDeclaredField("foo"); 

    Foo foo = (Foo)fooRef.get(null); 
    Bar bar = new Bar(foo); 
    fooRef.set(null, bar); 

}

Như đã nói tôi không biết nếu điều này là có thể trong trường hợp của bạn.

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