2016-07-05 18 views
8

Tôi đã bắt gặp một cái gì đó tôi thấy lạ trong Java và không thể tìm thấy nhiều thông tin về nó. Xét đoạn mã sau:Generics and Abstract Methods

public class TestClass { 

    private static abstract class AbstractClass { 
     abstract List<? extends Object> getList(); 
     abstract Map<Long, List<? extends Object>> getMap(); 
    } 

    private static final class ConcreteClass extends AbstractClass { 
     @Override 
     List<String> getList() { 
      return null; 
     } 

     @Override 
     Map<Long, List<String>> getMap() { 
      return null; 
     } 
    } 
} 

Trình biên dịch cho thấy một lỗi trên getMap() phương pháp:

getMap() in ConcreteClass cannot override getMap() in AbstractClass 
    return type Map<Long, List<String>> is not compatible with Map<Long, List<? extends Object>> 

Nhưng những lỗi tương tự là không có mặt đối với phương pháp getList(), nhưng tôi mong chờ hoặc cả hai để làm việc hoặc cả hai đều thất bại. Trong cả hai trường hợp, phương pháp ghi đè là delcaring List<String> thay cho List<? extends Object>. Ai đó có thể giải thích điều này?

Trả lời

10

Đó là vì có tồn tại chuyển đổi tiềm ẩn từ List<String> đến List<? extends Object>, nhưng không phải từ Map<Long, List<String>> đến Map<Long, List<? extends Object>>.

Tất cả các loại chung là bất biến trừ khi bạn đang sử dụng các loại ký tự đại diện. Vì không có ký tự đại diện trong các đối số kiểu chung của loại bản đồ "bên ngoài", nó không thể nắm bắt bất kỳ loại generic nào không khớp chính xác.

Nếu loại bản đồ của bạn là Map<Long, ? extends List<? extends Object>> thì nó sẽ hoạt động như bạn mong đợi. Một phần khác nếu câu trả lời là các lớp con có thể ghi đè hoặc thực hiện một phương thức siêu kiểu với một kiểu trả về khác, nhưng chỉ khi kiểu trả về của phương thức của kiểu con là chuyển đổi hoàn toàn thành kiểu trả về của kiểu siêu kiểu. Quay lại đầu trang (Trong Java 1.4 và dưới đây thậm chí sẽ không hoạt động: nó sẽ là một lỗi thời gian biên dịch nếu các loại không khớp chính xác.)

+0

Câu trả lời hay, cảm ơn! (Tôi sẽ chấp nhận sau khi hết thời hạn) – lucasvw

+3

điểm tốt, tôi muốn thêm '? mở rộng Object' có thể được thay thế bằng '?' mà không có bất kỳ hiệu ứng nào – Andrew

+2

@Andrew: chắc chắn, nhưng nguyên tắc tương tự áp dụng cho bất kỳ giới hạn dưới nào trên ký tự đại diện, không chỉ là 'Object'. –