2013-08-23 108 views
5

Gần đây tôi đã cố gắng chạy hai đoạn mã sau và đã rất ngạc nhiên khi xuất.Tính năng unboxing hoạt động như thế nào trong các biểu thức boolean ngắn mạch?

Đầu tiên:

// ... 
System.out.println((Boolean)null || true); 
// ... 

Thứ hai:

// ... 
System.out.println((Boolean)null || false); 
// ... 

Ví dụ kết quả đầu tiên trong kết quả sau:
đúng

Kết quả ví dụ thứ hai ở đầu ra sau đây:
Ngoại lệ trong chủ đề "chính" jav a.lang.NullPointerException
      tại com.blah.main (SanityCheck.java:26)

tôi sẽ có suy nghĩ cả hai ví dụ nên kết quả trong một con trỏ ngoại lệ null, như bất kỳ ngắn mạch được áp dụng trái bên phải. Nỗ lực để unbox boolean từ Boolean nên đã thất bại trước mặt bên kia của lôgíc hoặc được xem xét.

Bất cứ ai có thể giải thích hành vi không nhất quán này?

+0

Hành vi này có vẻ không phù hợp với [JLS] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24) "Vào thời gian chạy, bên trái Biểu thức toán hạng được đánh giá đầu tiên, nếu kết quả có kiểu Boolean, nó phải chuyển đổi unboxing " –

+2

SanityCheck.java – arynaq

Trả lời

2

Tôi sẽ sử dụng nó. Khi trình biên dịch cố gắng diễn giải hai câu lệnh, sự khác biệt chính là câu lệnh đúng với phía bên phải không bắt buộc phải thực hiện tính toán với Boolean thuận tay trái, trong khi câu lệnh sai ở phía bên phải là.

Boolean là một đối tượng, do đó nó có thể được đặt thành rỗng. Đó không phải là nơi ngoại lệ được ném ra. NullPointerException được ném ra khi bạn cố gắng thực hiện một phép toán trên một đối tượng Boolean được đặt thành null. Trong trường hợp thực sự, trình biên dịch sẽ truyền giá trị null vào Boolean, và vì OR'ing với true sẽ luôn mang lại giá trị true, điều kiện là đúng. Trong trường hợp sai, trình biên dịch sẽ truyền null vào Boolean một lần nữa, sau đó nó sẽ kiểm tra false, và nếu điều kiện là false, nó cần tính toán OR với Boolean vì điều kiện cuối cùng có thể là true hoặc false. Khi tính toán xảy ra, NullPointerException được ném.

+0

Đây là câu trả lời hay, nhưng tôi nghĩ rằng bất kỳ mạch ngắn nào diễn ra từ trái qua phải. Nếu toán hạng bên trái là đúng trong một hoặc toán hạng bên phải không được đánh giá. Tương tự, nếu toán hạng bên trái nó đúng trong một và toán hạng bên phải không được đánh giá.Tôi đoán nó có thể là một số tối ưu hóa bởi trình biên dịch, vì vậy tôi sẽ cố gắng dịch ngược tệp lớp. – studro

+0

Tôi thực sự nghĩ rằng tôi hiểu sai những gì bạn đã viết - ngắn mạch thậm chí không được áp dụng bởi vì điều này được tối ưu hóa tại thời gian biên dịch. Tại chỗ trên. – studro

+0

Chính xác! Vé chuyền và vé thật. Sau đó, không cần phải đúng OR * bởi vì nó sẽ luôn luôn đúng – user1549672

4

Tôi đã chạy tệp lớp thông qua JAD để xem mã được tối ưu hóa trông như thế nào. Đối với trường hợp đúng:

// ... 
System.out.println(true); 
// ... 

Đối với trường hợp sai:

// ... 
System.out.println(null.booleanValue()); 
// ... 
1

tôi không thể tái tạo kết quả của bạn. Tôi thực sự nhận được NPE cho cả hai trường hợp.

Theo JLS, biểu thức toán hạng bên trái luôn được đánh giá trước tiên. Khi (Boolean)null được đánh giá, tự động mở hộp được thực hiện trên một đối tượng Boolean rỗng. Cụ thể, mã cơ bản null.booleanValue() đang gây ra NPE.

+1

Bạn không nên nhận NPE cho trường hợp thực. (Boolean) null chỉ chạy tốt. Ngay cả khi nó được đánh giá đầu tiên, nó không nên ném một NullPointerException. – user1549672

+0

@ user1549672 Nó thực sự xảy ra với tôi, vì vậy tôi vẫn đang cố gắng tìm ra vấn đề. Liệu kết quả phụ thuộc vào phiên bản JDK tôi đang sử dụng? –

+0

Tôi không chắc chắn. Bạn đang chạy phiên bản nào? – user1549672