2012-12-15 14 views
13

Nếu tôi có thể tạo một lớp tùy ý mà không thực hiện tính năng tương đương, và cố gắng sử dụng nó như là một TreeSet, nó ném một ngoại lệ tại thời gian chạy khi một đối tượng được chèn vào:Tạo một TreeSet với một lớp không thể so sánh: tại sao ngoại lệ thời gian chạy, thay vì lỗi biên dịch?

public class Foo { 
} 

public TreeSet<Foo> fooSet = new TreeSet<Foo>(); 
fooSet.add(new Foo()); // Throws a ClassCastException exception here: Foo is not comparable 

Tôi không phải chuyên gia Java, nhưng một cái gì đó về điều này dường như gõ động (ala Python) theo cách tôi không mong đợi. Không có cách nào để thực hiện TreeSet để xác định rằng đối số kiểu chung của nó phải thực hiện Comparable sao cho nó có thể bị bắt tại thời gian biên dịch? Các hàm không chung chung có thể lấy các giao diện làm đối số; là không thể cùng với generics?

Trả lời

21

TreeSet được triển khai theo cách đó bởi vì bạn có thể alternatively provide a Comparator, trong trường hợp đó, các thành phần không cần phải là Comparable. Cách duy nhất để hỗ trợ cả hai hành vi mà không chia tách việc triển khai thành nhiều lớp là bao gồm kiểm tra thời gian chạy - đây chỉ đơn giản là quyết định thiết kế của tác giả (s) của lớp đó.

Hiển thị phương pháp nhà máy cho TreeSet thay vì các nhà xây dựng công cộng sẽ là cách duy trì kiểm tra thời gian biên dịch bằng cách sử dụng các ràng buộc kiểu chung chung chặt chẽ hơn, nhưng điều đó sẽ bị gián đoạn khỏi quy ước của API và sao chép các hàm tạo cho các lớp thực thi của nó. Như bạn đã lưu ý trong nhận xét của mình, Guava đi tuyến đường của nhà máy với các bộ sưu tập của nó và IMHO tốt hơn cho nó.

+2

Cảm ơn bạn - điều này có ý nghĩa hoàn hảo. Trong thực tế, tôi lưu ý rằng thư viện ổi của Google có [TreeMultiSet] (http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/TreeMultiset.html#create (java.util .Comparator)) class được thiết kế giống như bạn mô tả - với hai nhà máy, một trong số đó yêu cầu generic extend Comparable, và một trong số đó có một Comparator được đánh giá thích hợp. Tôi đoán họ đã quyết định sửa lỗi "thiết kế" để mang lại nhiều kiểm tra hơn để biên dịch thời gian. – uscjeremy

+2

Vâng, nó đặc biệt rắc rối rằng 'TreeSet' không thể thất bại cho đến khi bạn thực sự' đặt' một yếu tố mà không hoạt động, nhờ loại tẩy xoá. May mắn thay, nó ít nhất là một "đánh lừa tôi một lần" loại thất bại, nhưng vẫn còn khó chịu không để bắt nó tại thời gian biên dịch. –

+3

Tôi nghĩ rằng nó thực sự tồi tệ hơn - nếu tôi có một loạt các lớp con của 'Foo', và chỉ một số trong chúng thực hiện Comparable,' add' sẽ không ném một ngoại lệ cho đến khi một trong những Comparable không được đưa vào. Ai biết được khi nào điều đó cuối cùng sẽ xảy ra? Đây là một lựa chọn thiết kế bực bội: Tôi sử dụng Java qua các ngôn ngữ được gõ động một phần để tránh xa sự hỗn loạn của việc không kiểm tra kiểu cho đến khi mọi đường dẫn mã đã được thực hiện! – uscjeremy

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