2010-02-22 4 views
17

Tôi đang sử dụng Generics khá lâu nhưng tôi chưa bao giờ sử dụng công trình như List<? super T>.Ai đó có thể giải thích ý nghĩa của <? super T> là gì và khi nào nó nên được sử dụng và cách xây dựng này nên hợp tác với <T> và <? extends T>?

Điều đó có nghĩa là gì? Làm thế nào để sử dụng nó? Nó trông như thế nào sau khi tẩy xoá?

Tôi cũng tự hỏi: nó là một cái gì đó tiêu chuẩn trong lập trình chung (lập trình mẫu?) Hoặc nó chỉ là một java 'phát minh'? Ví dụ, C# có cho phép các công trình tương tự không?

Trả lời

9

Cấu trúc này được sử dụng khi bạn muốn tiêu thụ các mặt hàng từ bộ sưu tập vào bộ sưu tập khác. Ví dụ. bạn có một số chung là Stack và bạn muốn thêm phương thức popAll lấy Bộ sưu tập làm thông số và bật tất cả các mục từ ngăn xếp vào đó. Bởi lẽ thường, mã này nên quy phạm pháp luật:

Stack<Number> numberStack = new Stack<Number>(); 
Collection<Object> objects = ... ; 
numberStack.popAll(objects); 

nhưng nó biên dịch chỉ khi bạn xác định popAll như thế này:

// Wildcard type for parameter that serves as an E consumer 
public void popAll(Collection<? super E> dst) { 
    while (!isEmpty()) 
    dst.add(pop()); 
} 

Phía bên kia của đồng xu là pushAll cần được xác định như sau:

// Wildcard type for parameter that serves as an E producer 
public void pushAll(Iterable<? extends E> src) { 
    for (E e : src) 
    push(e); 
} 

cập nhật: Josh Bloch truyền mnemonic này để giúp bạn nhớ được loại ký tự đại diện để sử dụng:

PECS là viết tắt của producer-extends, consumer-super.

Để biết thêm chi tiết, hãy xem Effective Java 2nd Ed., Item 28.

+0

Java hiệu quả là rất tốt, nhưng tôi vẫn không có ấn bản thứ hai (( – Roman

+0

@Roman bạn có thể tải xuống chương về Generics từ liên kết tôi đã thêm :-) –

+0

Cảm ơn, tôi sẽ đọc nó. Có ai khác có 'chương mẫu' có sẵn miễn phí không? – Roman

4

Đây được gọi là "ký tự đại diện bị chặn". Nó được giải thích rất rõ ràng in the official tutorial.

Như đã nêu trong hướng dẫn này, bạn nên biết rằng danh sách này chứa các đối tượng chính xác một subtype của T

Ví dụ List<? extends Number> thể giữ chỉ Integer s hoặc chỉ Long s, nhưng không phải cả hai.

+2

' List số = Arrays.asList (1,5L); 'biên dịch tốt. Vì vậy, danh sách' số' đang giữ cả Int's và Long's. Tôi đang thiếu gì từ dòng cuối cùng của câu trả lời? – Geek

2

Những điều này được biết, về mặt lý thuyết loại, như sai, với <? extends T> là một ký hiệu đồng biến, và <? super T> là một ký hiệu ngược biến. Giải thích đơn giản nhất là ? có thể được thay thế bằng bất kỳ loại nào mở rộng T trong ký hiệu đồng biến, và ? có thể được thay thế bằng bất kỳ loại nào mà số T kéo dài trong biến thể ngược lại.

Sử dụng đồng và phương sai là khó khăn hơn nhiều so với lần đầu tiên có vẻ như, đặc biệt là do phương sai "chuyển đổi" tùy thuộc vào vị trí.

Ví dụ đơn giản sẽ là lớp chức năng. Giả sử bạn có hàm A và trả về một số B. Các ký hiệu chính xác cho nó sẽ là để nói rằng A là contra-biến thể và B os đồng biến thể.Để hiểu rõ hơn trường hợp này, hãy xem xét phương thức - hãy gọi nó là g - nhận hàm giả thuyết lớp này, trong đó f được cho là nhận được Arc2D và trả lại Shape.

Bên g, f này được gọi là đi qua một Arc2D và giá trị trả về được sử dụng để khởi tạo một Area (mà hy vọng một Shape).

Bây giờ, giả sử rằng số f bạn vượt qua nhận được bất kỳ Shape và trả lại Rectangle2D. Vì số Arc2D cũng là số Shape, sau đó g sẽ không gặp lỗi khi chuyển số Arc2D đến f và kể từ số Rectangle2D cũng là Shape, sau đó nó có thể được chuyển đến hàm tạo của Area.

Nếu bạn cố gắng đảo ngược bất kỳ phương sai nào hoặc hoán đổi các loại dự kiến ​​và thực tế trong ví dụ đó, bạn sẽ thấy nó không thành công. Bây giờ tôi không có thời gian để viết mã này, và Java của tôi khá gỉ ở mức nào đó, nhưng tôi sẽ xem những gì tôi có thể làm sau - nếu không ai đủ tốt để làm điều đó trước.

0

Câu hỏi thường gặp về Generics của Java có giải thích tốt về Generics Java. Kiểm tra câu hỏi What is a bounded wildcard? giải thích cách sử dụng cấu trúc "? Siêu T" trong chi tiết tốt.