2013-07-19 24 views
12

Nếu tôi có một lớp:Tại sao một lớp nguyên gốc Java xóa tất cả các generics thành đối tượng khi các tham số kiểu không xác định?

public class GenericClass<TBlah extends Number> { 
    public List<String> getList() { 
     return null; 
    } 
} 

Khi tôi cố gắng sử dụng phương pháp từ một lớp khác:

public class OtherClass { 
    public void test() { 
     GenericClass a = null; 
     for (String s : a.getList()) { 

     } 
    } 
} 

Tại sao a.getList() trả về một List<Object> cho đến khi tôi có sự thay đổi so với vòng lặp for để:

GenericClass<Number> a = null; 

Tại thời điểm này a.getList() trả về số List<String> như cần làm?

Chỉnh sửa: Tôi không hiểu tại sao hợp đồng được chỉ định bởi getList() phải bị ảnh hưởng bởi bất kỳ cách nào tôi khai báo biến 'a'. getList() luôn trả về một List<String>, không quan trọng những gì TBlah là.

+1

Uhm, tại sao khởi tạo nó thành 'null'? – fge

+0

@fge Đơn giản. Nó không liên quan đến vấn đề tôi nghĩ. – Xenoprimate

+7

Bởi vì đó là sự lựa chọn được thực hiện bởi các nhà văn của JLS. AFAIK, lý do là nếu bạn sử dụng các loại thô, bạn không quan tâm đến các loại generic. Giải pháp là tránh sử dụng các loại thô. –

Trả lời

8

Vì đây là cách làm việc của generics. Đừng quên rằng trước khi generics khi bạn tuyên bố một List nó là một danh sách các Object. Bạn đã được dự kiến ​​sẽ đặt/nhận Object và bạn đã bị buộc phải truyền để đưa đối tượng của bạn với đúng loại. Trên thực tế, vẫn còn danh sách Object trong thời gian chạy.

Generics là cách để trình biên dịch đảm bảo bạn nhập an toàn tại thời gian biên dịch giả sử bạn không có cảnh báo. Trong thời gian chạy không có List<String>. Chỉ có List. Trình biên dịch đặt tự động diễn viên cho bạn, vì vậy bạn có thể trong mã của bạn để viết String s = list.get(i) mà không cần đúc.

Khi bạn khai báo GenericClass a bạn đang khai báo một kiểu thô (bạn sẽ nhận được cảnh báo về điều này), do đó trình biên dịch không có cách nào để biết loại a.getList() được cho là sẽ trả lại. Vì vậy, nó sử dụng Object. Khi bạn khai báo GenericClass<Number> a = null; bây giờ trình biên dịch biết loại mong đợi cho a.getList() và sử dụng cái mong muốn.

Chỉnh sửa: Cần làm rõ rằng trình biên dịch có thể biết điều gì sẽ xảy ra nếu bạn tôn trọng hợp đồng chữ ký (ví dụ như trường hợp với GenericClass<Number>). Nếu bạn không tôn trọng hợp đồng (nghĩa là bạn đang sử dụng loại nguyên bản không extends Number) thì hợp đồng không áp dụng nữa. Trình biên dịch hoạt động như thể không có thông tin kiểu nào. Đừng quên rằng trình biên dịch cũng cần phải duy trì tính tương thích ngược với mã đã được tạo trong thời đại tiền Generics

+0

Đó là loại hợp lý. Nhưng tại sao trình biên dịch không biết a.getList() nên trả về cái gì? Nó ở ngay trong chữ ký của phương thức. Và điều đó không thay đổi bất kể tôi tuyên bố TBlah là gì ... Vậy tại sao tôi lại sử dụng kiểu thô? – Xenoprimate

+0

Thats không chính xác. Nó không có chữ ký. Chữ ký cho biết một 'blah mở rộng Số'. Bạn đã sử dụng một kiểu thô (tức là một 'Object' đơn giản) để chữ ký không áp dụng nữa vì' Object' không mở rộng 'Số' –

+1

Nhưng kiểu trả về của List trong getList() không bị ảnh hưởng bởi bất cứ thứ gì tôi chọn TBlah được. Vậy tại sao nó lại quan trọng? – Xenoprimate

-2

Bạn cần một nơi giữ/tài liệu tham khảo Danh mục để tham khảo và tài liệu tham khảo phải có cùng type.like,

Danh sách < String> x = a.getList();