Tại sao .compareTo () trong một giao diện trong khi .equals () nằm trong một lớp trong Java?


30

Tôi muốn biết lý do tại sao .compareTo()trong Comparablegiao diện trong khi một phương thức như .equalstrong Objectlớp. Đối với tôi, có vẻ như tùy tiện tại sao một phương thức như .compareTo()không có trong Objectlớp.

Để sử dụng .compareTo(), bạn thực hiện Comparablegiao diện và thực hiện .compareTo()phương thức cho mục đích của bạn. Đối với .equals()phương thức, bạn chỉ cần ghi đè phương thức trong lớp của bạn, vì tất cả các lớp kế thừa từ Objectlớp.

Câu hỏi của tôi là tại sao một phương thức như .compareTo()trong một giao diện mà bạn thực hiện chứ không phải trong một lớp như thế Objectnào? Tương tự như vậy, tại sao .equals()phương thức trong lớp Objectvà không phải trong một số giao diện được thực hiện?



2
Đây là một lựa chọn thiết kế của ngôn ngữ Java (không nhất thiết có nghĩa là nó là lựa chọn đúng). Trong các ngôn ngữ khác, ví dụ Haskell , bạn phải triển khai giao diện đẳng thức để có được sự bằng nhau về giá trị (thực ra bạn cung cấp một thể hiện cho kiểu chữ Eq).
mucaho

Câu trả lời:


58

Không phải tất cả các đối tượng có thể được so sánh, nhưng tất cả các đối tượng có thể được kiểm tra sự bình đẳng. Nếu không có gì khác, người ta có thể thấy nếu hai đối tượng tồn tại ở cùng một vị trí trong bộ nhớ (đẳng thức tham chiếu).

Nó có ý nghĩa gì compareTo()với hai Threadđối tượng? Làm thế nào là một chủ đề "lớn hơn" khác? Làm thế nào để bạn so sánh hai ArrayList<T>s?

Các Objecthợp đồng được áp dụng cho tất cả các lớp Java. Nếu thậm chí một lớp không thể so sánh với các thể hiện khác của lớp đó, thì Objectkhông thể yêu cầu nó là một phần của giao diện.

Joshua Bloch sử dụng các từ khóa "trật tự tự nhiên" khi giải thích lý do tại sao một lớp có thể muốn thực hiện Comparable. Không phải mọi lớp đều có một trật tự tự nhiên như tôi đã đề cập trong các ví dụ của tôi ở trên, vì vậy không phải mọi lớp nên thực hiện Comparablecũng như không nên ObjectcompareTophương thức.

... compareTophương thức không được khai báo Object. ... Nó tương tự như phương pháp Objectcủa equalsphương pháp, ngoại trừ việc nó cho phép so sánh thứ tự bên cạnh các so sánh đẳng thức đơn giản, và nó là chung chung. Bằng cách thực hiện Comparable, một lớp chỉ ra rằng các thể hiện của nó có một trật tự tự nhiên .

Java hiệu quả, Ấn bản thứ hai : Joshua Bloch. Mục 12, Trang 62. Dấu chấm lửng loại bỏ các tham chiếu đến các chương và ví dụ mã khác.

Đối với trường hợp bạn làm muốn áp đặt một trật tự trên một phi Comparablelớp mà không có một trật tự tự nhiên, bạn luôn có thể cung cấp một Comparatorví dụ để giúp sắp xếp nó.


3
Thậm chí còn vui hơn khi bạn bắt đầu nghĩ về việc so sánh với Exception (không phải là một lớp trừu tượng và do đó sẽ triển khai nó có nghĩa là aNullPulumException.compareTo (anUnsupportedFlavorException) sẽ có ... ý nghĩa?

10
tất cả các đối tượng có thể được kiểm tra tính bằng nhau trong Java có, nhưng nói chung là không. Có một số ví dụ về các đối tượng trong đó so sánh bằng không có ý nghĩa (thậm chí không phải là đẳng thức tham chiếu) - ví dụ: singletons. Có thể có các giao diện (các lớp trừu tượng) như ValueEquality và ReferenceEquality. Nó thậm chí có thể không phải là ý tưởng tồi ...
qbd

5
"tất cả các đối tượng có thể được kiểm tra sự bằng nhau. Nếu không có gì khác, người ta có thể thấy nếu hai đối tượng tồn tại ở cùng một vị trí trong bộ nhớ (đẳng thức tham chiếu)." - vì chúng ta có ==cái sau, cái này có một vòng rỗng với nó. Bỏ qua mặc định dư thừa, người ta có thể tìm thấy những lý do hợp lệ để không giả sử equalstrên tất cả các lớp, vì không phải tất cả các loại có thể hỗ trợ một mối quan hệ tương đương.
Raphael

3
Hai ví dụ về các loại không xác định được đẳng thức: luồng (ví dụ: lười biếng có khả năng liệt kê vô hạn hoặc số chính xác vô hạn) và các hàm. Cái trước có vấn đề là thiết lập sự bình đẳng có thể yêu cầu so sánh vô hạn. Quyết định nếu hai chức năng bằng nhau là không thể giải quyết được. Hỏi nếu hai trường hợp của các loại này tồn tại trong cùng một vị trí bộ nhớ là 1) không hữu ích và 2) cho phép khách hàng viết mã nhạy cảm với những gì nên thực hiện chi tiết. Hôm nay tôi có thể cung cấp cho bạn một ví dụ mới của cùng một danh sách vô hạn mỗi lần bạn hỏi, ngày mai tôi có thể ghi nhớ nó.
Doval

6
@Snowman Thực tế là nó vô dụng kết hợp với thực tế là phơi bày chi tiết thực hiện là lý do đủ để không cho phép nó. Khá nhiều lớp "dựa trên giá trị" trong Java 8 có một số câu nói sôi nổi "Chúng tôi không chịu trách nhiệm cho những gì xảy ra nếu bạn sử dụng ==" bởi vì cách các lớp đó được khởi tạo là một chi tiết triển khai nhưng ngôn ngữ khiến nó không thể che giấu. Bạn có thể nói rằng bất cứ ai so sánh hai Integers bằng cách tham chiếu là một thằng ngốc, nhưng cho phép bắt đầu so sánh là vẫn còn.
Doval

8

Các JLS §4.3.2 xác định classđối tượng theo cách sau:

4.3.2. Đối tượng lớp

Lớp Objectnày là một siêu lớp (§8.1.4) của tất cả các lớp khác.

Tất cả các kiểu lớp và mảng kế thừa (§8.4.8) các phương thức của lớp Object, được tóm tắt như sau:

  • Phương thức clonenày được sử dụng để tạo một bản sao của một đối tượng.

  • Phương thức equalsxác định một khái niệm về đẳng thức đối tượng, dựa trên giá trị, không tham chiếu, so sánh.

  • Phương thức finalizenày được chạy ngay trước khi một đối tượng bị hủy (§12.6).

  • Phương thức getClasstrả về đối tượng Class đại diện cho lớp của đối tượng.

  • Một Classđối tượng tồn tại cho từng loại tham chiếu. Ví dụ, nó có thể được sử dụng để khám phá tên đủ điều kiện của một lớp, các thành viên của nó, siêu lớp trực tiếp của nó và bất kỳ giao diện nào mà nó thực hiện.

    Các loại của một biểu thức gọi phương pháp getClassClass<? extends |T|>nơi Tlà lớp hoặc giao diện tìm kiếm (§15.12.1) cho getClass.

    Một phương thức lớp được khai báo synchronized(§8.4.3.6) đồng bộ hóa trên màn hình được liên kết với đối tượng Class của lớp.

  • Phương thức hashCodenày rất hữu ích, cùng với phương thức bằng, trong các hashtables như java.util.Hashmap.

  • Các phương pháp wait, notifynotifyAllđược sử dụng trong lập trình sử dụng chủ đề đồng thời (§17.2).

  • Phương thức toStringtrả về một chuỗi đại diện của đối tượng.

Vì vậy, đó là lý do equalslà trong Objectnhưng compareTolà trong một giao diện riêng biệt. Tôi sẽ suy đoán rằng họ muốn giữ Objecttối thiểu nhất có thể. Có lẽ họ đã tìm ra rằng gần như tất cả Objects sẽ cần equalshashCode(đó thực sự chỉ là một hình thức kiểm tra sự bình đẳng) nhưng không phải tất cả các đối tượng sẽ cần phải có một khái niệm về trật tự , đó là những gì compareTođược sử dụng cho.


Tôi đoán về mặt lý thuyết có thể có một giao diện Equitable<T>nhưng nếu Objectthực hiện nó, thì mỗi lớp sẽ là một giao diện Equitable<Object>. Tại thời điểm đó, có một sự khác biệt? Trong thực tế không thực sự, trong phức tạp có.
Thuyền trưởng Man

1
@CaptainMan Trong .Net, objectcũng Equals(object)giống như trong Java, nhưng cũng có IEquatable<T>giao diện. Mặc dù lý do chính để nó tồn tại là để tránh quyền anh khi Tlà một loại giá trị, điều này là không thể có trong Java.
Svick

hashCode không phải là một hình thức kiểm tra đẳng thức, bởi vì có các xung đột băm. nếu A và B bằng nhau, chúng có cùng mã băm, nhưng nếu A và B có cùng mã băm, điều này không có nghĩa là chúng bằng nhau!
Josef

trên thực tế, câu trả lời của bạn sẽ rất có lợi từ việc chuyển sang một JLS cũ ( titanium.cs.berkeley.edu/doc/java-langspec-1.0.pdf ) - nó có báo giá tốt hơn về lý do tại sao equalsđược khai báo trong Objecttrực tiếp: The methods equals and hashCode are declared for the benefit of hashtables such as java.util.Hashtable (§21.7)- như thiết kế Java tương thích ngược, lựa chọn thiết kế Java 1.0 là lý do thực tế cho equalsviệc nó ở đâu.
vaxquis

vì bản chỉnh sửa mà tôi đã đề xuất có thể sẽ bị từ chối vì "quá quyết liệt", trong trường hợp bạn muốn chỉ Ctrl + C / Ctrl + V các nội dung có liên quan vào câu trả lời của bạn: pastebin.com/8c4EpLRX
vaxquis

2

Ngoài câu trả lời tuyệt vời của Snowman, hãy nhớ rằng đó Comparablelà một giao diện chung trong một thời gian dài. Một kiểu không thực hiện compareTo(object), nó thực hiện compareTo(T)ở đâu Tlà kiểu riêng của nó. Điều này không thể được thực hiện trên object, vì objectkhông biết lớp sẽ bắt nguồn từ nó.

objectcó thể đã định nghĩa một compareTo(object)phương thức, nhưng điều này sẽ cho phép không chỉ những gì Snowman chỉ ra, so sánh giữa hai ArrayList<T>s hoặc giữa hai Threads, mà thậm chí là so sánh giữa một ArrayList<T>và a Thread. Điều đó thậm chí còn vô nghĩa hơn.


0

Giả sử tôi có hai tham chiếu đối tượng: X xác định một thể hiện của Stringviệc giữ nội dung "George"; Y xác định trường hợp Pointgiữ tọa độ [12,34]. Hãy xem xét hai câu hỏi sau:

  • X và Y có xác định các đối tượng tương đương không?

  • X nên sắp xếp trước, sau hay tương đương với Y?

Việc X và Y xác định các trường hợp thuộc loại không liên quan không gây ra vấn đề gì khi xem xét câu hỏi đầu tiên. Các đối tượng chỉ có thể được coi là tương đương nếu các loại của chúng có chung một cơ sở xác định chúng là tương đương; vì StringPointkhông có cơ sở như vậy (loại cơ sở chung duy nhất của chúng liên quan đến tất cả các đối tượng riêng biệt là không tương đương), câu trả lời chỉ đơn giản là "không".

Tuy nhiên, thực tế là các loại không liên quan, tuy nhiên, đặt ra một vấn đề lớn liên quan đến câu hỏi thứ hai. Một số loại xác định mối quan hệ đặt hàng giữa các phiên bản của chúng và một số mối quan hệ đặt hàng thậm chí có thể mở rộng trên nhiều loại [ví dụ: có thể BigIntegerBigDecimalxác định các phương thức so sánh cho phép các thể loại của một trong hai loại được xếp hạng so với các thể hiện của loại khác], nhưng Nói chung, không thể lấy hai trường hợp tùy ý và hỏi "Nên sắp xếp X trước, sau hoặc tương đương với Y" và rút ra tổng số đơn đặt hàng. Có thể hỏi "X nên sắp xếp trước, sau, tương đương hoặc không liên kết với Y" nếu các đối tượng được yêu cầu báo cáo một thứ tự nhất quán mặc dù không phải là tổng sốmột, nhưng hầu hết các thuật toán sắp xếp yêu cầu tổng thứ tự. Do đó, ngay cả khi tất cả các đối tượng có thể thực hiện một compareTophương thức nếu "unroped" là một trả về hợp lệ, thì phương thức đó sẽ không đủ hữu ích để chứng minh sự tồn tại của nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.