2012-02-28 33 views

Trả lời

11

Có.

List<Base> có thể chứa một hỗn hợp các thứ khác nhau có nguồn gốc từ Base. List<? extend Base> chứa các mục đồng nhất (theo nghĩa là tất cả chúng phải xuất phát từ một số loại không xác định, cụ thể mà lần lượt xuất phát từ Base).

Đặt một cách khác, List<? extends Base> là lớp cơ sở cho List<T extends Base>. Vì vậy, bạn có thể vượt qua một List<T extends Base> cho bất kỳ phương pháp nào có một List<? extends Base>. Điều này cũng không đúng đối với các phương thức lấy số List<Base>.

+6

Cụ thể, bạn không thể thêm đối tượng thuộc loại 'Cơ sở' vào 'Danh sách '. –

+3

@LouisWasserman: Không chỉ vậy, nhưng bạn không thể thêm * bất kỳ * đối tượng nào (ngoại trừ 'null') vào một' Danh sách ', bởi vì bạn không biết loại'? 'đại diện cho cái gì. –

+0

@LouisWasserman: Tóm lại, Danh sách có thể được chuyển đến bất kỳ phương thức nào có hoặc là List , Danh sách , Danh sách hoặc Danh sách ? Vậy tại sao mọi người lại muốn sử dụng Danh sách ? Điều gì cũng khiến tôi khó hiểu là bạn có thể làm .add (...) trên cả hai List và danh sách , trong đó '...' có thể là bất kỳ thứ gì là Cơ sở hoặc có nguồn gốc (trực tiếp hoặc gián tiếp) từ Cơ sở. – user113454

5

List<Base> list có thể chứa các thành phần thuộc loại Base hoặc bất kỳ loại phụ nào của nó. Một số ví dụ với các lớp JDK:

List<Object> objects = new ArrayList<Object>(); 
objects.add(new Object()); // adding an Object instance 
objects.add("I am a String"); // a String instance is also an Object 
objects.add(Integer.valueOf(5)); // an Integer instance is also an Object 

Nhưng khi bạn lấy các yếu tố, bạn có thể gán cho họ chỉ cho các biến của lớp Object, vì Object là tham số loại danh sách công bố.

Object first = objects.get(1); 
Object second = objects.get(2); 
Object third = objects.get(3); 

lớp thời gian chạy thực của họ vẫn còn Object, StringInteger, vì vậy bạn có thể bỏ chúng với những loại và làm việc với họ như vậy, nhưng dàn diễn viên như vậy có thể thất bại khi chạy với một ClassCastException nếu không được thực hiện đúng và nó nói chung không phải là một ý tưởng hay khi làm việc với các danh sách theo cách như vậy.

List<? extends Base> list là tuyên bố không thực sự được chỉ định để khai báo biến, vì như đã đề cập trong nhận xét của Daniel Pryden - bạn không thể add() đối tượng nào trong đó, chỉ null s.

List<? extends String> list = new ArrayList<? extends String>(); 
list.add("a String")); // compile error! 

Nhưng bạn có thể sử dụng như một biểu hiện bị chặn wildcard cho các thông số phương pháp chung. Một ví dụ từ List bản thân là phương pháp addAll() có chữ ký là thế này:

boolean addAll(Collection<? extends E> c); 

này cho phép bạn làm điều gì đó như thế này:

List<String> strings = Arrays.asList("a", "b"); 
List<Object> objects = new ArrayList<Object>(); 
objects.addAll(strings); 

Nếu không có sự <? extend E> wildcard nó sẽ không thể để thêm các số String s đó vào số List của Object s, vì các loại chung (không giống như mảng) không phải là covariant. Điều đó có nghĩa là List<String>không phải là một loại phụ của List<Object>. Nhưng bất kỳ String là một Object, phải không? Do đó, cần phải khai báo tham số phương thức với ký tự đại diện bị chặn - a List<String> một loại phụ của List<? extends Object>.

Một lần nữa, tôi phải chỉ ra - ký tự đại diện bị ràng buộc chủ yếu được chỉ định cho thông số phương thức chung, không cho các kiểu trả về phương thức hoặc khai báo biến.

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