2011-12-26 22 views
13

Các mã sauTại sao một diễn viên chung của Danh sách <? mở rộng Set ..> thành Danh sách <Set..> thành công trên Sun JDK 6 nhưng không biên dịch được trên Oracle JDK 7?

class GenericCompilationFailureDemo { 
    List<? extends GenericCompilationFailureDemo> newList() { 
     return new ArrayList<GenericCompilationFailureDemo>(); 
    }; 

    void useList() { 
     List<GenericCompilationFailureDemo> list = 
      (List<GenericCompilationFailureDemo>) newList(); 
    } 

    List<? extends Set<GenericCompilationFailureDemo>> newListOfSpecificSets() { 
     return new ArrayList<Set<GenericCompilationFailureDemo>>(); 
    }; 

    void useListOfSpecificSets() { 
     List<Set<GenericCompilationFailureDemo>> listOfSpecificSets = 
      (List<Set<GenericCompilationFailureDemo>>) newListOfSpecificSets(); 
    } 

    List<? extends Set<? extends GenericCompilationFailureDemo>> newListOfSets() { 
     return new ArrayList<Set<? extends GenericCompilationFailureDemo>>(); 
    }; 

    void useListOfSet() { 
     List<Set<? extends GenericCompilationFailureDemo>> listOfSets = 
      (List<Set<? extends GenericCompilationFailureDemo>>) newListOfSets(); 
    } 
} 

biên dịch dưới Sun JDK 1.6.0_20 (64-bit trên Windows Vista, nhưng tôi không nghĩ rằng làm cho bất kỳ sự khác biệt) nhưng gây ra sự thất bại biên soạn sau đây theo Oracle JDK 1.7.0_01 (giống nền tảng):

[ERROR] src\main\java\GenericCompilationFailureDemo.java:[56,78] error: inconvertible types 

Lưu ý rằng người đầu tiên hai "kéo dài-to-cụ thể-loại" phôi trong useListuseListOfSpecificSets cả vẫn thành công dưới 1.7.0_01, vì vậy nó sẽ có vẻ nó là cái gì để làm với "đôi mở rộng chung".

Bất kỳ ý tưởng nào có thể đã thay đổi từ 6 đến 7 và liệu hành vi được quan sát có theo thông số hoặc lỗi không?

sửa để đáp ứng với bình luận Sanjay của:

@Sanjay: Aha, thú vị! Ở đây, sản lượng từ java -version:

java version "1.7.0_01" 
Java(TM) SE Runtime Environment (build 1.7.0_01-b08) 
Java HotSpot(TM) 64-Bit Server VM (build 21.1-b02, mixed mode) 

Và đây là kết quả của javac GenericCompilationFailureDemo.java (cùng một mã như trên với báo cáo nhập khẩu đối với List, ArrayList và Set):

GenericCompilationFailureDemo.java:30: error: inconvertible types 
      (List<Set<? extends GenericCompilationFailureDemo>>) newListOfSets() 
; 
                      ^
    required: List<Set<? extends GenericCompilationFailureDemo>> 
    found: List<CAP#1> 
    where CAP#1 is a fresh type-variable: 
    CAP#1 extends Set<? extends GenericCompilationFailureDemo> from capture of ? 
extends Set<? extends GenericCompilationFailureDemo> 
Note: GenericCompilationFailureDemo.java uses unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 
1 error 
+1

Đối với những gì nó có giá trị, mã này biên dịch trên JDK của tôi 7. Bạn có thể gửi toàn bộ sản lượng của 'java -version' lệnh cùng với "xây dựng " chuỗi? –

+0

vui lòng dán các lỗi biên dịch chính xác + những gì sanjay đã đề xuất. * Tôi tin rằng các generics được cho là hơi đơn giản trong java 7 * trong một số trường hợp ... có thể bạn đã tìm thấy một trường hợp góc mà cú pháp cũ hơn, phức tạp, JDK 6 phá vỡ trình biên dịch mới. – jayunit100

+0

@Sanjay: aha, thú vị! Xem câu hỏi đã chỉnh sửa để trả lời nhận xét của bạn –

Trả lời

7

Đây rõ ràng là một lỗi javac7. Nó nên được phép cho mỗi quy tắc chuyển đổi đúc [1]

Một trong những quy tắc cho phép chuyển đổi tài liệu tham khảo hẹp ... tiếp theo là một chuyển đổi không được kiểm soát

Đúc List<A> => List<B> được phép bởi quy tắc này

List<A> => List // narrowing reference conversion 
List => List<B> // unchecked conversion 

Đó không phải là tất cả câu chuyện; spec có các quy tắc khác để cấm truyền như List<String>=>List<Integer>, vì chúng là được phân biệt rõ ràng được tham số các loại. Không có đối tượng thuộc về hai loại cùng một lúc, do đó, trình biên dịch nghĩ rằng nó tốt hơn để không cho phép lỗi lập trình rõ ràng này. (Bạn có thể bỏ qua nó bằng cách rõ ràng List<String>=>List=>List<Integer>)

Quy tắc cuối cùng không áp dụng ở đây; do đó, nó trông giống như một lỗi javac7.

Tại sao quy tắc cuối cùng không áp dụng: vì vậy chúng tôi đang truyền List<? extends A> đến List<A>. Tại đây, chuyển đổi bắt được áp dụng cho List<? extends A> [2] vì vậy, chúng tôi đang thực sự đúc List<T> đến List<A>, trong đó T là biến loại mới có giới hạn trên A.

Câu hỏi đặt ra là liệu List<T>List<A>các loại tham số được phân biệt rõ ràng là. Sự hiểu biết của tôi là nó sai (nó phải là sai lầm cho hai ví dụ đầu tiên của bạn để biên dịch). Vì T là biến kiểu, nên có thể có giá trị để làm cho List<T>List<A> cùng một loại tham số (ví dụ: khi T=A). Lý do này sẽ làm việc cho bất kỳ loại A.

[1] http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5

[2] http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#341306

+0

_Bạn có thể bỏ qua nó bằng cách rõ ràng Danh sách => Danh sách => Danh sách ) _ Tôi đã xác minh đó, thực sự - nhưng "hack generics" không phải là cái gì tôi thực sự muốn cam kết ;-) Cảm ơn lời giải thích! Có ai trong Oracle bạn muốn đề nghị liên lạc (ví dụ: danh sách trình biên dịch-dev hay không?) Để xem liệu nó có đáng để nộp một lỗi cho điều này không? –

+0

danh sách trình biên dịch-dev phải là tốt – irreputable

+1

Chỉ được đăng lên trình biên dịch-dev. Tò mò để xem loại phản hồi nào chúng tôi sẽ nhận được ;-) –

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