Xin lỗi, nhưng bạn không thể.
Khai báo ký tự đại diện List<? extends Number> foo3
có nghĩa là biến foo3
có thể giữ bất kỳ giá trị nào từ một họ các loại (chứ không phải bất kỳ giá trị nào của một loại cụ thể). Nó có nghĩa là bất kỳ trong số này là nhiệm vụ pháp lý:
List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number
Vì vậy, với điều này, loại đối tượng nào bạn có thể thêm vào List foo3
đó sẽ hợp pháp sau bất kỳ ArrayList
nhiệm vụ nào có thể có ở trên :
- Bạn không thể thêm một
Integer
vì foo3
có thể chỉ vào a List<Double>
.
- Bạn không thể thêm một
Double
vì foo3
có thể chỉ vào a List<Integer>
.
- Bạn không thể thêm một
Number
vì foo3
có thể chỉ vào a List<Integer>
.
Bạn không thể thêm bất kỳ đối tượng nào vào List<? extends T>
vì bạn không thể đảm bảo loại đối tượng List
đó thực sự đang trỏ đến, vì vậy bạn không thể đảm bảo rằng đối tượng được phép trong đó List
. "Đảm bảo" duy nhất là bạn chỉ có thể đọc từ nó và bạn sẽ nhận được một T
hoặc lớp con của T
.
Logic ngược áp dụng cho super
, ví dụ List<? super T>
. Đây là hợp pháp:
List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number
Bạn không thể đọc loại T cụ thể (ví dụ Number
) từ List<? super T>
vì bạn không thể đảm bảo loại nào List
thực sự được trỏ đến. "Đảm bảo" duy nhất bạn có là bạn có thể thêm giá trị của loại T
(hoặc bất kỳ lớp con nào T
) mà không vi phạm tính toàn vẹn của danh sách được trỏ đến.
Ví dụ hoàn hảo về điều này là chữ ký cho Collections.copy()
:
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Lưu ý cách src
khai báo danh sách sử dụng extends
để cho phép tôi chuyển bất kỳ Danh sách nào từ một nhóm Danh sách liên quan và vẫn đảm bảo rằng nó sẽ tạo ra các giá trị của loại T hoặc các lớp con của T. Nhưng bạn không thể thêm vào src
danh sách.
Các dest
công dụng khai danh sách super
cho phép tôi để vượt qua bất kỳ Danh sách từ một gia đình của các loại sách có liên quan và vẫn đảm bảo tôi có thể viết một giá trị của một loại hình cụ thể T vào danh sách đó. Nhưng nó không thể được đảm bảo để đọc các giá trị của loại T cụ thể nếu tôi đọc từ danh sách.
Vì vậy, bây giờ, nhờ các ký tự đại diện, tôi có thể thực hiện bất kỳ cuộc gọi nào trong số đó bằng phương thức duy nhất đó:
// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());
Hãy xem xét mã khó hiểu và rất rộng này để rèn luyện trí não của bạn. Các dòng nhận xét là bất hợp pháp và lý do tại sao được nêu ở cực bên phải của dòng (cần phải cuộn để xem một số trong số họ):
List<Number> listNumber_ListNumber = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>(); // error - can assign only exactly <Number>
//List<Number> listNumber_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Number>
List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>();
List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>();
List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>(); // error - Integer is not superclass of Number
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>(); // error - Double is not superclass of Number
//List<Integer> listInteger_ListNumber = new ArrayList<Number>(); // error - can assign only exactly <Integer>
List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Integer>
//List<? extends Integer> listExtendsInteger_ListNumber = new ArrayList<Number>(); // error - Number is not a subclass of Integer
List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a subclass of Integer
List<? super Integer> listSuperInteger_ListNumber = new ArrayList<Number>();
List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a superclass of Integer
listNumber_ListNumber.add(3); // ok - allowed to add Integer to exactly List<Number>
// These next 3 are compile errors for the same reason:
// You don't know what kind of List<T> is really
// being referenced - it may not be able to hold an Integer.
// You can't add anything (not Object, Number, Integer,
// nor Double) to List<? extends Number>
//listExtendsNumber_ListNumber.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Number>
//listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer>
//listExtendsNumber_ListDouble.add(3); // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double>
listSuperNumber_ListNumber.add(3); // ok - allowed to add Integer to List<Number> or List<Object>
listInteger_ListInteger.add(3); // ok - allowed to add Integer to exactly List<Integer> (duh)
// This fails for same reason above - you can't
// guarantee what kind of List the var is really
// pointing to
//listExtendsInteger_ListInteger.add(3); // error - can't add Integer to *possible* List<X> that is only allowed to hold X's
listSuperInteger_ListNumber.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
listSuperInteger_ListInteger.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
List<? extends Number>
đó không có nghĩa là "danh sách các đối tượng thuộc các loại khác nhau, tất cả đều mở rộngNumber
". Nó có nghĩa là "danh sách các đối tượng của một loại duy nhất mở rộngNumber
".