2015-09-16 12 views
6

Trong đoạn mã Java sau, tôi đã tạo một danh sách nums. Tôi có thể chỉ định một danh sách khác trong quá trình khai báo. Nhưng không thể thêm các mục mới ngoại trừ null. Vì vậy, nó có nghĩa là nums là chỉ đọc? Tại sao? Có thể thêm các mục mới vào danh sách đó không?"? Extends ParentClass" chỉ đọc?

List<Integer> ints = new ArrayList<Integer>(); 
ints.add(1); 
ints.add(2); 

List<? extends Number> nums = ints; 
nums.add(3.14); //Generates error 
nums.addAll(ints); //Generates error 

nums.add(null);  //works 
System.out.println(nums.get(0)); //works 

Tôi đã trải qua link này. Tôi không thể có được lý do chính xác.

+0

Tôi không biết, lưu ý rằng nums.add ((Số) new Double (3.14)); kết quả trong lỗi: Phương thức thêm (capture # 1-of? extends Number) trong danh sách loại không áp dụng cho các đối số (Số) –

+1

Xem câu hỏi này: http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs – Natix

+0

đây là một quan niệm sai lầm rất phổ biến; nhưng quan niệm hoạt động trong hầu hết các trường hợp :) – ZhongYu

Trả lời

5

Is it possible to add new items in that list?

Không ... vì mã đó không biết danh sách là "thực sự". Hãy tưởng tượng nếu bạn thể:

List<String> strings = new ArrayList<>(); 
List<? extends Object> objects = strings; // This is fine 
objects.add(new Object()); // Fortunately this *isn't* valid... 
System.out.println(strings.get(0).length()); // Or what would this do? 

Về cơ bản, khi bạn sử dụng một ký tự đại diện như ? extends T bạn có thể chỉ nhận được giá trị ra qua API ... và khi bạn sử dụng một ký tự đại diện như ? super T, bạn chỉ có thể đặt các giá trị trong qua API - bởi vì đó là điều an toàn.

+0

vì vậy, chúng ta có thể nói danh sách sẽ chỉ đọc? –

+4

@PradipKharbuja: Không, không hẳn. Bản thân danh sách không phải là chỉ đọc - bạn vẫn có thể thêm vào nó thông qua 'ints', hoặc loại bỏ nó thông qua' nums'. Bạn không thể * thêm * vào 'nums' vì an toàn kiểu. –

-1

Generics chỉ là thời gian biên dịch.

Vậy Trình biên dịch sẽ quyết định loại thực tế chúng ta sẽ sử dụng là gì.

List<? extends Number> 

Điều đó có nghĩa là chúng tôi không chắc chắn loại đối tượng thực tế nào.

Vì vậy Trình biên dịch không đảm bảo loại danh sách thực tế có.

2

Không, nó không chỉ đọc ... mặc dù đó thường là ý định.

Cho đối tượng List<? extends Number>, trình biên dịch converts loại của nó là List<X> trong đó X là một loại phụ không xác định của Số. Do đó, đối tượng có phương thức add(X). Chúng ta có thể gọi phương thức với đối số X ... ví dụ: null.

Và kể từ get() lợi nhuận X, chúng ta cũng có thể gọi add() với một giá trị từ get() .... Trực tiếp gọi list.add(list.get(i)) sẽ không làm việc, mặc dù nó có ý nghĩa. Chúng tôi sẽ cần một chút helper.

Ví dụ cổ điển là Collections.reverse(List<? extends Object> list). Phương pháp này sẽ sửa đổi list, mặc dù ký tự đại diện.

Bạn cũng có thể gọi các phương pháp đột biến như clear(), tất nhiên, trên bất kỳ danh sách nào.


Điều đó đang được nói, ký tự đại diện thực sự là chủ yếu để sử dụng tại chỗ variance, và thường xuyên nhất, nó truyền đạt ý định từ nhà thiết kế API cho dù một loại tham số là dành cho trong hoặc ra. Ví dụ: bằng cách khai báo List<? super/extends Foo>, API thể hiện rằng nó có ý định tiêm T vào hoặc, lấy T ra khỏi, danh sách.

Đó là quan niệm sai lầm rằng ký tự đại diện chỉ đọc/ghi. Nhưng quan niệm sai lầm này hoạt động trong hầu hết các trường hợp sử dụng. Và càng có nhiều người có quan niệm sai lầm này, càng có nhiều nó trở thành một ước ...

xem bài viết của tôi trên wildcard - http://bayou.io/draft/Capturing_Wildcards.html

0

Nó giúp khi bạn nghĩ về List<? extends Number> nums như một List của một số loại điều mà kéo dài Number , nhưng bạn không thể chắc chắn những gì. Như vậy, mọi thứ bạn làm với nums cần có thể thực hiện được với một điều như vậy.

Thêm null hoạt động vì null có thể được bỏ vào bất kỳ thứ gì. Mọi thứ khác bạn cố gắng thêm sẽ thất bại, bởi vì trình biên dịch không thể chắc chắn 100% rằng thứ bạn đang thêm sẽ mở rộng thứ mà danh sách được tạo ra.

Thay vì List<? extends Number> nums do List<Number> nums, bởi vì bạn vẫn có thể đặt bất kỳ thứ gì mở rộng Number.

? không có nghĩa là "bất cứ điều gì", nó gần với ý nghĩa "một số cụ thể nhưng không xác định".