2017-10-22 19 views
9

Tôi đang đọc mã nguồn java và tôi đã tìm thấy những thứ như sau:
http://www.java2s.com/Code/JavaAPI/java.util/newTreeSetEComparatorsuperEc.htm
Tại sao các nhà xây dựng của TreeSet <E> chấp nhận các siêu tham số của E thay vì mở rộng của E

I don' t hiểu tại sao tham số của hàm tạo này là <? super E>.

Theo hiểu biết của tôi, nó phải là <? extend E> thay vì <? super E> vì nếu E có thể so sánh, con cái của E phải so sánh được trong khi cha mẹ của E có thể không.

Trả lời

14

Hãy xem xét ba lớp: Drink, Juice extends Drink, và OrangeJuice extends Juice.

Nếu tôi muốn TreeSet<Juice>, tôi cần một bộ so sánh sẽ so sánh hai loại nước trái cây này. Tất nhiên, Comparator<Juice> sẽ thực hiện việc này.

A Comparator<Drink> cũng sẽ làm điều này, bởi vì nó có thể so sánh bất kỳ hai loại đồ uống nào, và do đó bất kỳ hai loại nước ép nào.

A Comparator<OrangeJuice> sẽ không làm điều này. Nếu tôi muốn thêm AppleJuice vào bộ nước ép của tôi, không tương thích với bộ so sánh này vì nó chỉ có thể so sánh các loại nước cam.

7

Bạn tạo một bộ chuối được sắp xếp. Để làm điều đó, bạn cần có khả năng so sánh chuối. Do đó bạn có thể sử dụng một so sánh của chuối để làm điều đó. Nhưng nếu bạn có một bộ so sánh có thể sắp xếp bất kỳ loại trái cây nào (kể cả chuối), thì nó cũng sẽ hoạt động. Vì vậy, bạn cũng có thể sử dụng Comparator<Fruit> hoặc thậm chí là Comparator<Food> để sắp xếp chuối của mình.

Đó là lý do tại sao sử dụng Comparator<? super E>.

Nếu đó là Comparator<? extends E>, bạn sẽ có thể tạo bộ chuối với Comparator<DriedBanana>. Nhưng điều đó sẽ không hiệu quả: một so sánh chuối khô chỉ có thể so sánh chuối khô. Không phải tất cả các loại chuối.

Để biết thêm thông tin, cũng đọc What is PECS (Producer Extends Consumer Super)?

4

nên thay vì vì E là so sánh, con cái của E phải so sánh được trong khi bố mẹ của E có thể không.

Comparator không phụ thuộc vào các đối tượng Comparable.
Nó thậm chí thường được sử dụng như là một thay thế hoặc bổ sung.

Trong thực tế, constructor này

public TreeSet(Comparator<? super E> comparator) {...} 

có thể là:

public TreeSet(Comparator<E> comparator) {... } 

Nhưng bằng cách xác định một kí hiệu wildcard bao thấp hơn, các nhà phát triển JDK cung cấp linh hoạt hơn cho các lớp khách hàng bằng cách cho phép các Comparator được tương thích với cả các cá thể lớp hiện tại và các cá thể lớp cha. Trong một số trường hợp, nó có thể có ý nghĩa.

Bây giờ này:

public TreeSet(Comparator<? extend E> comparator) { 

không thể có giá trị vì nó có nghĩa là bạn có thể kết thúc với một phương pháp compare() mà xác định loại lớp con như thông số.
Nhưng các phần tử của Set có thể chứa các phiên bản của một phân lớp cụ thể nhưng không chỉ.

Imagine mã này:

TreeSet<CharSequence> set = new TreeSet<>(new Comparator<String>() { 

    @Override 
    public int compare(String o1, String o2) { 
     ... 
    } 
}); 

set.add("string"); 
set.add(new StringBuilder()); 
... 

Tôi muốn so sánh String s nhưng Set có thể chứa String trường mà còn bất kỳ lớp con của CharSequence như StringBuilder, CharBuffer, vv ...
Và nếu CharSequence là không phải là abstract, nó cũng có thể chứa các phiên bản của chúng.

Với ví dụ này, chúng tôi hiểu rằng khái niệm Comparator<? extend E> là sai.

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