2016-12-13 14 views
9

Khi tôi chạy mã Java sau:Các ClassLoader có thể thay thế mảng bởi bất cứ điều gì

ClassLoader c = new ClassLoader() { 
    @Override 
    public Class<?> findClass(String name) { 
     return Object.class; 
    } 
}; 

Class<?> cc = c.loadClass(Object[][].class.getName()); 

System.out.println(cc.getName()); 

tôi nhận được java.lang.Object tại nhà ga hiển thị, ngay cả khi tôi thay Object[][].class.getName() bởi [[Ljava.lang.Object trong các mã. Vấn đề là tôi đã mong đợi giao diện điều khiển hiển thị [[Ljava.lang.Object.

Trong thực tế, trong JVM specification, tôi có thể đọc phần sau đây:

Một lớp mảng được tạo ra trực tiếp bởi Java Virtual Machine (§5.3.3), chứ không phải bởi một bộ nạp lớp. Tuy nhiên, lớp định loader của D được sử dụng trong quá trình tạo mảng lớp C.

Kể từ Object[][] là một lớp mảng, tôi cho rằng findClass của tôi sẽ không được gọi với đối số [[Ljava.lang.Object nhưng với yếu tố của nó nhập java.lang.Object.

Hơn nữa, trong phần "Tạo lớp Array", thuật toán đệ quy là thực sự mô tả:

Nếu loại thành phần là một loại tài liệu tham khảo, thuật toán của phần này (§5.3) được áp dụng một cách đệ quy sử dụng lớp loader L để tải và do đó tạo ra các kiểu thành phần của C.

Vì vậy, câu hỏi của tôi là:

  • tại sao tôi nhận outp này ut? Nó có nghĩa là tôi phải tự bao gồm thuật toán đệ quy này bên trong ClassLoader của tôi, thay vì để JVM làm việc đó cho tôi? Nếu đây là ý nghĩa của nó, cách tốt nhất để làm điều đó là gì?
  • Tôi có hiểu sai về "được tạo" trong báo giá đầu tiên không? Liệu nó chỉ có nghĩa là tôi không thể tạo ra các lớp mảng thời gian chạy, nhưng tôi vẫn có thể vá tải của nó?
+1

Điểm OP là spec có vẻ chỉ ra rằng trong trường hợp các lớp mảng, JVM tránh sử dụng trình nạp lớp và nạp trực tiếp lớp đó. Và đây là một câu hỏi rất hay. –

+0

Có, tôi đã làm điều này có mục đích để vá tải của loại phần tử của mảng (chỉ để kiểm tra). Nhưng thay vào đó, nó thay thế toàn bộ mảng. – Codoscope

Trả lời

4

Bạn đang hỏi về đặc điểm JVM, nhưng thử nghiệm của bạn thể hiện hành vi của java.lang.ClassLoader, một lớp độc lập là "invoked by the Java virtual machine to resolve class references". Nếu JVM đang nạp một lớp mảng, nó sẽ bỏ qua trình nạp lớp hoàn toàn. Điều này có thể được chứng minh bằng cách cho phép JVM cố gắng tải các lớp học với một bộ nạp lớp tùy chỉnh:

Class<?> clazz = Class.forName("[[Lcom.foo.Test;", true, new ClassLoader() { 
    @Override 
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 
     System.out.println("Loading " + name); 
     return super.loadClass(name, resolve); 
    } 
}); 
System.out.println(clazz); 

Output:

 
Loading com.foo.Test 
class [[Lcom.foo.Test; 

Như bạn có thể thấy, các loại thành phần ban đầu được nạp thông qua bộ nạp lớp , nhưng các loại mảng được tải ngầm.

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