2013-03-22 35 views
6

Tiếp theo là các mã từ lớp java.lang.System (JDK phiên bản 1,6)lạ 'ra khỏi' biến, System.out.println()

public final static PrintStream out = nullPrintStream(); //out is set to 'null' 

private static PrintStream nullPrintStream() throws NullPointerException { 
    if (currentTimeMillis() > 0) { 
     return null; 
    } 
    throw new NullPointerException(); 
} 

khi chúng tôi viết System.out.println("Something"); trong mã của chúng tôi thì tại sao don' t chúng tôi nhận NullPointerException thậm chí khi 'ra' được thiết lập để 'null'

Nhưng dù sao out sẽ được thiết lập thông qua sau setOut phương thức trong lớp Hệ thống

public static void setOut(PrintStream out) { 
    checkIO(); 
    setOut0(out); 
} 

Họ n tại sao JLS cần phương pháp nullPrintStream?

+0

'if (currentTimeMillis()> 0) {return null; } '=> thật sự kỳ quặc .. Trong JDK 7, nó đơn giản là:' public printStream tĩnh out = null; '. – assylias

+1

@assylias Đó là tất cả để xoa dịu các phiên bản trước của trình biên dịch javac/JIT. Nếu không có 'if' trình biên dịch có thể nhận ra nó luôn luôn trả về' null' và biên dịch 'out' như là một hằng số biên dịch, với tất cả các hậu quả xấu. –

+0

Điều này có nghĩa là một khi đã đủ thời gian để làm cho giá trị 'currentTimeMillis()' tràn giá trị lớn nhất cho một 'long', tất cả các ứng dụng đang chạy với các máy ảo cũ hơn Java 7, sẽ thất bại với một lỗi:' java.lang .ExceptionInInitializerError Gây ra bởi java.lang.NullPointerException tại java.lang.System.nullPrintStream (Unknown Source) 'hoặc tương tự. – gparyani

Trả lời

8

Hãy nhìn vào các private static void initializeSystemClass() - Phương pháp này được gọi là để bắt đầu mọi thứ lên, nó gọi setOut0() là phương pháp native. Điều này liên kết các Stream vào nơi nó được cho là.

Vì vậy, mặc dù trường có thể trôngpublic static final thực tế là không, mã native sẽ thay đổi nó.

EDIT

OP hỏi Vậy tại sao JLS cần phương pháp nullPrintStream?

Điều này là để làm với trình biên dịch java - nó sẽ "nội tuyến" static final trường nếu chúng được gán cho một hằng số tại thời gian biên dịch, như null. Trình biên dịch sẽ thực sự thay thế mỗi tham chiếu đến trường bằng hằng số.

Điều này sẽ phá vỡ khởi tạo vì các đối tượng sẽ không còn giữ tham chiếu đến số Stream mà là null. Gán luồng cho sự trở lại của một phương thức ngăn cản nội tuyến.

Một số người có thể gọi đây là một vụ tấn công dơ bẩn. Để đánh lừa Bismarck "JDK giống như xúc xích, tốt nhất là không thấy nó được làm".

+0

Mặc dù như đã nhận xét ở trên, trong Java 7 nó đã được sửa chữa - vì vậy nó phải làm với các trình biên dịch cũ hơn như được chỉ ra bởi Marko. – assylias

+0

Họ có thể đã xác định 'công thức tĩnh cuối cùng PrintStream ra = null;'. Giúp hiểu trường cuối cùng tĩnh "lnline". – AmitG

+2

@AmitG hãy xem [this] (http://stackoverflow.com/questions/5173372/java-static-final-values-replaced-in-code-when-compiling) và [this] (http: // docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.9). Nếu bạn định nghĩa một thứ gì đó dưới dạng hằng số thời gian biên dịch thì trình biên dịch (Java 6) sẽ sử dụng thông tin đó để tối ưu hóa mã - nó sẽ thay thế bất kỳ tham chiếu nào bằng chữ. Vì vậy, bất cứ điều gì mà nói 'System.out' sẽ được thay thế bằng' null' bởi trình biên dịch vì nó giả định rằng 'System.out' không thể thay đổi vì nó được đặt thành' null' và nó là 'final'. –

2

Đây chỉ là cách lớp System.out được intialised.

Ngoài ra còn có một phương pháp:

private static native void setOut0(PrintStream out); 

nào được gọi là bằng phương pháp sau:

private static void initializeSystemClass() { 
2

System.in, out và err được quản lý bởi JVM từ mã gốc. Toàn bộ ma thuật này với nullPrintStream() đã ở đó để giữ cho javac không gạch chân vào các trường này. Vì java 7 có vẻ như

public final static PrintStream out = null; 
Các vấn đề liên quan