2014-12-26 23 views
5

Tại sao Java có thể suy ra tổ tiên chung của nhiều loại giới hạn trên, nhưng không phải là loại giới hạn dưới?Suy luận kiểu Java với các loại giới hạn dưới

Cụ thể hơn, hãy xem xét các ví dụ sau:

static class Test { 

    static <T> T pick(T one, T two) { 
     return two; 
    } 

    static void testUpperBound() { 
     List<? extends Integer> extendsInteger = new ArrayList<>(); 

     // List<? extends Integer> is treated as a subclass of List<? extends Number> 
     List<? extends Number> extendsNumber = extendsInteger; 

     // List<? extends Number> is inferred as the common superclass 
     extendsNumber = pick(extendsInteger, extendsNumber); 
    } 

    static void testLowerBound() { 
     List<? super Number> superNumber = new ArrayList<>(); 

     // List<? super Number> is treated as a subclass of List<? super Integer> 
     List<? super Integer> superInteger = superNumber; 

     // The inferred common type should be List<? super Integer>, 
     // but instead we get a compile error: 
     superInteger = pick(superNumber, superInteger); 

     // It only compiles with an explicit type argument: 
     superInteger = Test.<List<? super Integer>>pick(superNumber, superInteger); 
    } 
} 
+0

Thử nghiệm của bạn biên dịch cho tôi mà không có đối số loại rõ ràng bằng cách sử dụng 1.8.0_25. – Alex

+0

@Alex Tôi đang sử dụng 1.7. Có lẽ nó đã được sửa. – shmosel

Trả lời

1

Tôi nghĩ rằng tôi có thể giải thích tại sao Java phân biệt giữa một thấp hơn lại loại giới hạn và giới hạn trên.

Cố gắng suy ra giới hạn dưới thường gặp có thể không thành công khi sử dụng các giới hạn không tương thích, ví dụ: IntegerLong. Khi chúng tôi đang sử dụng một ràng buộc trên, nó luôn luôn có thể tìm thấy một số giới hạn trên phổ biến, trong trường hợp này List<? extends Number>. Nhưng không có giới hạn thấp hơn phổ biến của List<? super Integer>List<? super Long>. Lựa chọn an toàn duy nhất trong trường hợp xung đột như vậy là trả lại List<? extends Object>, đồng nghĩa với List<?>, có nghĩa là "a List loại không xác định".

Bây giờ, được cho là chúng ta có thể phải dùng đến điều đó chỉ khi thực sự có các giới hạn xung đột, trái ngược với trường hợp trong câu hỏi của tôi. Nhưng có lẽ nó đã được quyết định để có những cách dễ dàng ra và không giả định có một giới hạn thấp hơn phổ biến trừ khi xác định rõ ràng.

0

Tôi đang sử dụng 1.8.0_25 và tôi nhận được lỗi biên dịch. Lỗi, tuy nhiên, không phải là cuộc gọi để chọn là xấu, nhưng biến mà bạn muốn đưa kết quả vào. Lặp đi lặp lại ví dụ của bạn:

static void testLowerBound() { 
    List<? super Number> superNumber = new ArrayList<>(); 
    List<? super Integer> superInteger = superNumber; 

    // this gets the error 
    superInteger = pick(superNumber, superInteger); 
    // this doesn't 
    pick(superNumber, superInteger); 

    // what's happening behind is 
    List<? extends Object> behind = pick(superNumber, superInteger); 
    superInteger = behind; 
    // that last line gets the same compilation error 
} 

Nếu bạn nhìn vào cách T đang được thay thế trong các cuộc gọi, các thông số được sử dụng như List, mất thông tin về các ràng buộc thấp hơn.

Giới thiệu về suy luận: Mọi? không chính xác là "bất kỳ thứ gì có thể được gán cho ..." nhưng "một loại cụ thể mà tôi không muốn đặt tên, có thể được gán cho ...". Nó quan trọng bởi vì trong ví dụ của bạn, bạn nhận được 3 biến, 1 cho mỗi danh sách và một biến khác, một biến khác nhau, cho kết quả chọn. Bây giờ, do khai báo chọn, sự thay thế cho T phải thỏa mãn thứ bậc lớp của các tham số. Trong trường hợp đầu tiên, bạn cần thay thế cho < # 1 mở rộng số nguyên> và < # 2 mở rộng số>. # 2 có thể là Double, do đó, đầu mối tốt nhất bạn có là # 3 mở rộng Number. Trong trường hợp thứ hai, bạn cần thay thế cho < # 1 super Integer> và < # 2 super Number>. Điều đó có nghĩa là số 2 có thể là bất kỳ ai trong số, đối tượng, có thể tuần tự; # 1 thêm vào danh sách đó Comparable và Integer. Các kết hợp có thể là Number, Object (và T nên là Object); hoặc Serializable, Integer (và T có thể được Serializable), do đó, các đầu mối tốt nhất nó có là T là một danh sách của một loại không rõ mở rộng Object.

Tất nhiên nó chỉ có thể đạt đến Number, nhưng bạn không thể có được hai giới hạn cho biến cùng loại, vì vậy phải để cho nó ở đó

+0

Tôi không thấy lý do của bạn. Cũng giống như chúng ta thay đổi ràng buộc thành superclass chung gần nhất ('Number') với' extends', chúng ta nên chuyển nó thành lớp con chung gần nhất ('Integer') với' super'. – shmosel

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