Bối cảnh:
Tôi có một lớp MainTest có nhiều nút, mỗi nút khởi tạo một lớp mà tôi đang mã hóa/kiểm tra. Tôi muốn chu kỳ mã/kiểm tra cho các lớp này được nhanh chóng, và thấy hiệu quả của những thay đổi của tôi một cách nhanh chóng, một vài lần một phút. MainTest mà là ổn định mất khoảng 20 giây để tải, mà sẽ không là một vấn đề tôi đã không cần thiết để tải lại nó cho mỗi thay đổi trong các lớp học nó instantiates. Tôi muốn tải MainTest một lần, và khi nó khởi tạo một lớp khác, hãy gọi nó là ChildTest, nhiều lần (khi sự kiện nút), nó sẽ tải lại phiên bản mới nhất của ChildTest.
Câu hỏi ngắn gọn:
Làm cách nào để bạn biết lệnh java 'mới' để tải lại lớp từ đĩa chứ không phải từ bộ nhớ cache jvm?
Tôi đã thử Class.ForName nhưng nó không tạo sự khác biệt.
Tôi cũng đã thử sử dụng trình nạp lớp tùy chỉnh (được sao chép từ nguồn mở), không có kết quả.Làm cách nào để buộc Java tải lại lớp khi khởi tạo?
Trả lời
Không có hy vọng "quá tải" toán tử new
nhưng bạn chắc chắn có thể viết trình nạp lớp tùy chỉnh mà chỉ cần tải lại bytecode mỗi lần bạn yêu cầu tải lớp. Không có trình nạp lớp ngoài hộp nào sẽ làm những gì bạn đang tìm kiếm vì tất cả chúng đều cho rằng định nghĩa lớp sẽ không thay đổi trong suốt vòng đời của JVM.
Nhưng dưới đây là cách bạn thực hiện điều đó. Tạo trình nạp lớp có tên là Reloader
ghi đè phương pháp loadClass
và findClass
để chúng đơn giản tải lại tệp lớp từ đĩa mỗi khi chúng được gọi (thay vì "lưu bộ nhớ cache" để sử dụng sau này). Sau đó, bạn chỉ cần gọi new Reloader().loadClass("foo.bar.MyClassName")
bất kỳ lúc nào bạn nghi ngờ định nghĩa lớp đã thay đổi (ví dụ như một phần trong các phương pháp vòng đời của khung thử nghiệm của bạn).
This article điền vào một số chi tiết nhưng bỏ lỡ một số điểm quan trọng, đặc biệt là về việc sử dụng các phiên bản mới của trình nạp lớp để tải lại sau đó và ủy quyền cho trình nạp lớp mặc định khi thích hợp. Dưới đây là một ví dụ làm việc đơn giản mà nhiều lần nạp lớp MyClass
và giả định tập tin lớp học tồn tại trong tương đối "./bin" thư mục:
public class Reloader extends ClassLoader {
public static void main(String[] args) throws Exception {
do {
Object foo = new Reloader().loadClass("MyFoo").newInstance();
System.out.println("LOADED: " + foo); // Overload MyFoo#toString() for effect
System.out.println("Press <ENTER> when MyFoo.class has changed");
System.in.read();
} while (true);
}
@Override
public Class<?> loadClass(String s) {
return findClass(s);
}
@Override
public Class<?> findClass(String s) {
try {
byte[] bytes = loadClassData(s);
return defineClass(s, bytes, 0, bytes.length);
} catch (IOException ioe) {
try {
return super.loadClass(s);
} catch (ClassNotFoundException ignore) { }
ioe.printStackTrace(System.out);
return null;
}
}
private byte[] loadClassData(String className) throws IOException {
File f = new File("bin/" + className.replaceAll("\\.", "/") + ".class");
int size = (int) f.length();
byte buff[] = new byte[size];
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
dis.readFully(buff);
dis.close();
return buff;
}
}
Tại mỗi lời gọi của 'làm/trong khi' khối trong phương thức main , một Trình tải lại mới được khởi tạo để tải lớp từ đĩa và trả về cho người gọi. Vì vậy, nếu bạn ghi đè tệp bin/MyClass.class
để chứa triển khai mới với phương thức khác nhau, quá tải toString
, thì bạn sẽ thấy việc triển khai mới mỗi lần.
Tôi thực sự đang làm việc với CustomClassLoader của bài viết đó, nhưng tôi đang gặp sự cố khi làm điều đó để làm những gì tôi muốn. Nghe có vẻ giống như cách tiếp cận đúng, nhưng tôi sẽ phải đào sâu vào bài báo, tôi đoán vậy. – nat101
Bạn sẽ cần phải cẩn thận không sử dụng toán tử "mới" cho lớp thay đổi hoặc trình quản lý lớp hệ thống mặc định sẽ được sử dụng thay cho của bạn. Hãy thử sử dụng một cái gì đó như thế này thay vì 'MyClass foo = myReloader.loadClass (" MyClass "). NewInstance();' – maerics
Có! Nó thực hiện công việc. Ngay cả đối với một gui. Cảm ơn. – nat101
Tôi không chắc chắn cách thực hiện điều này bằng mã, nhưng NetBeans có nút "Áp dụng thay đổi mã" sẽ thực hiện việc này.
Tuy nhiên, nó chỉ có thể thay đổi việc triển khai lớp, nó không thể thay đổi chữ ký của nó. Điều này có nghĩa là bạn không thể thêm, xóa hoặc thay đổi các biến hoặc phương thức của cá thể. Điều này là do thiết kế của JVM không cho phép chúng được thay đổi khi một lớp đã được nạp một lần.
Vì NetBeans có thể thực hiện, phải có cách, nhưng tôi không biết cách thực hiện thủ công.
Nếu bạn chạy trong một IDE hỗ trợ tính năng này, bạn có thể chỉ cần nhấp vào nút mỗi lần bạn sửa đổi một lớp. Sau đó nó sẽ biên dịch lại lớp đó và tải lại nó.
Tôi đang sử dụng Eclipse tự động biên dịch khi lưu. Câu hỏi là làm thế nào để có được lớp vừa được biên dịch nạp vào một jvm mà alread có phiên bản trước đó của cùng một lớp được nạp. – nat101
Có vẻ như bạn muốn ot sử dụng triển khai nóng khi có thể được sử dụng với trình gỡ lỗi. Khi bạn gỡ lỗi một vấn đề và recomiple một số các lớp học của nó, bạn có thể nhận được tùy chọn để tải lại các lớp học đã thay đổi.
EDIT: Ngoài việc sử dụng API gỡ lỗi, bạn có thể sử dụng Thiết bị đo đạc. http://download-llnw.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html
Tuy nhiên, vì việc sử dụng trình gỡ lỗi là cách đơn giản nhất để thực hiện việc này, nếu cách này không hiệu quả, bạn có thể gặp phải sự cố tương tự.
Nghe có vẻ giống như những gì bạn cần để kiểm tra các tác phẩm nhỏ hơn, vì vậy phải mất ít hơn một lần chạy một số tập con của ứng dụng của bạn.
Hoặc bạn có thể tải ứng dụng của mình nhanh hơn bằng cách cung cấp cơ sở đổ và tải lại cho bộ nhớ. Bằng cách này, bạn có thể bắt đầu ứng dụng của mình từ ảnh chụp nhanh (có thể ngay lập tức)
Tôi thực sự không thể sử dụng trình gỡ lỗi cho mục đích này, quá chậm. (gui rộng rãi.) Nhưng câu hỏi của tôi là, nếu trình gỡ rối có thể làm điều đó, tại sao tôi không thể? – nat101
Bạn có thể nếu bạn sử dụng API gỡ lỗi để làm điều đó. Tuy nhiên, điều này không đơn giản để sử dụng. Việc thay đổi trình nạp lớp sẽ không thay đổi một lớp đã được nạp thay đổi mã của nó. xem chỉnh sửa. –
Nghe có vẻ hơi đáng sợ, nhưng điều này sẽ hữu ích.
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html
ClassLoader có thể tự động tải các lớp học trong thời gian chạy, tôi sẽ đọc các api để xác định nếu tải nó một lần nữa ghi đè các phiên bản trước.
Tôi sẽ cần phải viết lớp con ClassLoader của riêng mình để thực hiện việc này. – nat101
Điều này sẽ không thực sự khó khăn, chỉ cần mở rộng ClassLoader và chọn luôn tạo một cá thể mới từ tệp nguồn. API cung cấp tổng quan ngắn gọn về cách bạn có thể thực hiện việc này để tự động nhận tệp từ mạng. Trường hợp của bạn sẽ là từ một nguồn tập tin không đổi. – Valchris
Tôi đã tìm thấy một bài viết về chính xác vấn đề này.
http://www.zeroturnaround.com/blog/reloading-objects-classes-classloaders/
NHƯNG, câu trả lời maerics cũng có vẻ tốt. sẽ thử nó sau.
Bạn có thể thử xem Java Rebel. Nó là một trình tải lớp "chỉ phát triển" được thiết kế để làm chính xác những gì bạn cần nhưng, có lẽ, nó có thể tốn kém cho nhu cầu của bạn. Trong trường hợp của bạn, giải pháp của Peter Lawrey có thể là đủ.
- 1. Làm cách nào để buộc IE tải lại javascript?
- 2. Làm cách nào để bắt buộc ActiveRecord tải lại lớp học?
- 3. Buộc tải lớp
- 4. Làm cách nào để vô hiệu hóa "Khởi tạo công cụ Java" khi khởi động Eclipse?
- 5. Khi nào khởi động lại và không tải lại Nginx?
- 6. Làm cách nào để khởi động lại hoặc đặt lại các thuộc tính của một lớp?
- 7. C# - Khởi tạo lại lớp tĩnh?
- 8. Làm cách nào để buộc tải lại tập lệnh và thực thi lại?
- 9. Cách khởi tạo mảng trong java khi hàm tạo của lớp có các tham số?
- 10. java, khởi tạo lớp con từ SuperClass
- 11. Làm cách nào để lặp lại một lớp tạo của tôi trong Java?
- 12. Làm cách nào để lập trình và khởi tạo một lớp Java một cách có lập trình?
- 13. Làm cách nào để tôi tải lại JSP được lưu trữ trên web khi khởi động lại
- 14. Làm cách nào để buộc làm mới trang hoặc tải lại trong jQuery?
- 15. Khởi tạo một lớp bằng trình khởi tạo siêu lớp
- 16. Làm thế nào để khởi tạo lớp bên trong với sự phản ánh trong Java?
- 17. buộc văn bản RequireJS! để tải lại
- 18. Làm cách nào để buộc QtCreator tải tệp pro.user?
- 19. Làm cách nào để làm cho trang tải lại của Firefox khi nhấn nút quay lại?
- 20. Cách khởi tạo một lớp học?
- 21. Buộc khởi tạo một HwndHost
- 22. Làm cách nào để khởi tạo lại tính hợp lệ của jQuery?
- 23. Làm cách nào để khởi tạo một std :: vector trong một hàm tạo lớp trong C++?
- 24. Java Keystore tải lại trong khi đang chạy
- 25. Khi nào khởi tạo lớp tĩnh xảy ra?
- 26. Làm cách nào để tải lại định nghĩa lớp trong ipython
- 27. Có cách nào để buộc một trình nạp lớp tải gói ngay cả khi không có lớp nào của nó được tải?
- 28. Java: cách khởi tạo String []?
- 29. Làm cách nào để kiểm soát ClassLoader nào sẽ tải lớp học?
- 30. Làm cách nào để buộc vẽ lại danh sách xem?
bạn đang sử dụng một khung kiểm tra như JUnit hay nó là một testbench trong nước? –
lớp thử nghiệm trong nước. – nat101