2013-09-11 114 views
6

Mã dưới đây (Java) có hợp pháp không?Khi nào nó hợp pháp để so sánh các đối tượng và nguyên thủy với toán tử '=='?

class Test { 
    Object foo() {return "";} 
    boolean bar() {return foo() == true;} 
} 

Nó sẽ không biên dịch với JDK 6 nhưng có vẻ tốt trên 7+. Sự thay đổi đặc biệt? Đã sửa lỗi? Tôi đã thảo luận tại http://bugs.eclipse.org/bugs/show_bug.cgi?id=416950 và có thể đi theo cách này.

+2

kiểm tra bài đăng trước đó, [sự khác biệt trong autoboxing java6 và java7] (http://stackoverflow.com/questions/16119638/differences-in-auto-unboxing-between-java-6-vs-java-7) – nachokk

Trả lời

1

Khi nó quay ra, nó là không hợp pháp để so sánh nguyên thủy với biểu thức kiểu thời gian biên dịch 'Đối tượng'. JLS 15.21 rõ ràng cấm nó:

Các nhà khai thác bình đẳng có thể được sử dụng để so sánh hai toán hạng có mui trần (§5.1.8) để loại số, hoặc hai toán hạng kiểu boolean hoặc Boolean, hoặc hai toán hạng mà mỗi một trong hai loại tham chiếu hoặc loại trống. Tất cả các trường hợp khác dẫn đến lỗi biên dịch.

Trình biên dịch Eclipse đánh dấu lỗi bất kể phiên bản Java.Đối với Java 7, cả Oracle JDK và OpenJDK đều cho phép mã biên dịch. Điều này bug trong Oracle và JDK mở được sửa chữa trong phiên bản 8.

Tóm lại, so sánh này là bất hợp pháp theo thông số và sẽ chỉ biên dịch trên một số tập hợp con cho một tập con cụ thể của mục tiêu phiên bản ngôn ngữ. Sẽ không bao giờ làm việc trên Java 4- hoặc 8+. Chuyển đổi truyền được đề cập trong các câu trả lời khác chỉ áp dụng cho toán tử '=', không áp dụng cho '=='. 15.21.3 chỉ áp dụng cho hai toán hạng tham chiếu.

0

Dưới đây là các mã byte để tham khảo

class Test { 
    Test(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>": 
     4: return 

    java.lang.Object foo(); 
    Code: 
     0: ldc   #2     // String 
     2: areturn 

    boolean bar(); 
    Code: 
     0: aload_0 
     1: invokevirtual #3     // Method foo:()Ljava/lang/Object; 
     4: iconst_1 
     5: invokestatic #4     // Method java/lang/Boolean.valueOf: 
     8: if_acmpne  15 
     11: iconst_1 
     12: goto   16 
     15: iconst_0 
     16: ireturn 
} 

Biên soạn với

java version "1.7.0_25" 
Java(TM) SE Runtime Environment (build 1.7.0_25-b17) 
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode) 

Nó dường như được chuyển đổi trở thành một StringBoolean mà được không có hộp bọc.

3

JLS về bình đẳng tham khảo không thay đổi giữa java 6 & 7:

Chapter 15.21.3: Reference Equality Operators == and !=:

Nếu toán hạng của một nhà điều hành bình đẳng đều của một trong hai tài liệu tham khảo loại hoặc kiểu null, sau đó hoạt động là đối tượng bình đẳng.

Đây là lỗi thời gian biên dịch nếu không thể chuyển đổi loại hoặc toán hạng sang loại khác bằng chuyển đổi truyền (§5.5). Giá trị thời gian chạy của hai toán hạng nhất thiết phải là không bằng nhau.

Tuy nhiên, tôi nhận thấy một số thay đổi trên Chapter 5.5: Casting Conversion. Việc đưa boolean vào đối tượng dường như được phân loại là quy ước đấm bốc trên Java 7:

Biểu thức của kiểu nguyên thủy có thể chuyển đổi thành loại tham chiếu mà không bị lỗi.

enter image description here

⊡ nghĩa chuyển đổi đấm bốc

Do đó kể từ khi nguyên thủy true có thể được đúc để Object, biểu hiện bình đẳng của bạn có thể được phân loại như bình đẳng tham khảo trên Java 7, và không mang lại lỗi biên dịch