2012-02-05 25 views
9

Xin giải thích đang wildcard generic này biên dịch lỗi thời gian:Tạo đối tượng chung chung mới với ký tự đại diện

//no compile time error. 
List<? extends Number> x = new ArrayList<>(); 

//compile time error. 
List<? extends Number> x = new ArrayList<? extends Number>(); 
+0

Phiên bản Java nào? – Bill

+2

ví dụ đầu tiên hoạt động trên java 7 rõ ràng và không phải trên java 6 kể từ khi kim cương tùy chọn werent được cho phép trong 6. ví dụ thứ hai không thành công trong cả hai –

+1

Đầu tiên chắc chắn sẽ không làm việc trên 6; không có nhà điều hành kim cương. Đối với phần còn lại; bạn có thể muốn kiểm tra tài nguyên này: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html – Bill

Trả lời

22

Cú pháp không hợp lệ để khởi tạo loại chung với ký tự đại diện. Loại List<? extends Number> có nghĩa là List của một số loại hoặc mở rộng Number. Để tạo một thể hiện của loại hình này không có ý nghĩa, bởi vì với instantiation bạn đang tạo một cái gì đó cụ thể:

new ArrayList<? extends Number>();//compiler:"Wait, what am I creating exactly?" 

loại Generic với các kí hiệu chỉ có ý nghĩa cho các biến và các thông số phương pháp, bởi vì điều này cho phép tự do hơn trong những gì có thể được chỉ định/truyền vào chúng.

//compiler:"Okay, so passing in a List<Integer> or a List<Double> are both fine" 
public void eatSomeNumbers(List<? extends Number> numbers) { 
    for (Number number : numbers) { 
     System.out.println("om nom " + number + " nom"); 
    } 
} 

Đảm bảo lưu ý những hạn chế đi kèm với sử dụng ký tự đại diện.

List<? extends Number> numList = ... 
numList.add(new Integer(3));//compiler:"Nope, cause that might be a List<Double>" 

Đối với ví dụ đầu tiên của bạn, kim cương là một tính năng mới trong Java 7 cho phép trình biên dịch để suy luận loại trường hợp tổng quát mới, dựa trên kiểu của biến nó gán cho. Trong trường hợp này:

List<? extends Number> x = new ArrayList<>(); 

Trình biên dịch rất có thể suy luận new ArrayList<Number>() ở đây, nhưng những gì đang suy ra những vấn đề khó, miễn là đó là một nhiệm vụ có giá trị vào biến nhất định. Đây là lý do cho các nhà điều hành kim cương được giới thiệu - mà chỉ định loại chung của một đối tượng mới là thừa, như dài một số loại loại chung sẽ làm cho nó một phân công hợp lệ/đối số.

Lý do này chỉ có ý nghĩa nếu bạn nhớ rằng generics trong Java là một tính năng ngôn ngữ thuần túy biên dịch, vì type erasure và không có ý nghĩa khi chạy. Ký tự đại diện chỉ tồn tại vì giới hạn này. Ngược lại, trong thông tin loại C# chung quanh các thời gian chạy - và các ký tự đại diện chung không tồn tại trong ngôn ngữ đó.

+0

+1: Giải thích rất chi tiết –

+0

Có cách nào để vượt qua giới hạn này khi khởi tạo các lớp ẩn danh không? – shmosel

+0

@shmosel Tôi không nghĩ như vậy, nhưng tôi không chắc chắn về lợi ích sẽ là gì, ví dụ: 'mới Foo () {}' trên 'mới Foo () {}'. Bạn có thể giải thích thêm về trường hợp sử dụng của mình không? –

1

Sử dụng

List<? extends Number> x = new ArrayList<Number>(); 

để thay thế.

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