Mengapa .compareTo () dalam antarmuka sementara .equals () berada di kelas di Jawa?


30

Saya ingin tahu mengapa .compareTo()ada di Comparableantarmuka sementara metode seperti .equalsdi Objectkelas. Bagi saya, tampaknya sewenang-wenang mengapa metode seperti .compareTo()belum ada di Objectkelas.

Untuk menggunakan .compareTo(), Anda mengimplementasikan Comparableantarmuka dan mengimplementasikan .compareTo()metode untuk tujuan Anda. Untuk .equals()metode, Anda cukup mengganti metode di kelas Anda, karena semua kelas mewarisi dari Objectkelas.

Pertanyaan saya adalah mengapa metode seperti .compareTo()di antarmuka yang Anda implementasikan daripada di kelas seperti Object? Demikian juga, mengapa .equals()metode di kelas Objectdan bukan di beberapa antarmuka yang harus diimplementasikan?



2
Ini adalah pilihan desain bahasa Jawa (tidak selalu berarti itu adalah pilihan yang tepat). Dalam bahasa lain, misalnya Haskell , Anda harus mengimplementasikan antarmuka kesetaraan untuk mendapatkan kesetaraan nilai (sebenarnya Anda memberikan contoh pada Eqtypeclass).
mucaho

Jawaban:


58

Tidak semua objek dapat dibandingkan, tetapi semua objek dapat diperiksa untuk kesetaraan. Jika tidak ada yang lain, seseorang dapat melihat apakah dua objek ada di lokasi yang sama dalam memori (referensi kesetaraan).

Apa artinya compareTo()dua Threadbenda? Bagaimana satu utas "lebih besar dari" yang lain? Bagaimana Anda membandingkan dua ArrayList<T>s?

The Objectkontrak berlaku untuk semua kelas Java. Jika bahkan satu kelas tidak dapat dibandingkan dengan contoh lain dari kelasnya sendiri, maka Objecttidak dapat mengharuskannya untuk menjadi bagian dari antarmuka.

Joshua Bloch menggunakan kata-kata kunci "pemesanan alami" ketika menjelaskan mengapa kelas mungkin ingin diterapkan Comparable. Tidak setiap kelas memiliki urutan alami seperti yang saya sebutkan dalam contoh saya di atas, jadi tidak setiap kelas harus menerapkan Comparableatau Objectmemiliki compareTometode.

... compareTometode ini tidak dinyatakan dalam Object. ... Hal ini mirip dalam karakter Object's equalsmetode, kecuali bahwa hal itu memungkinkan perbandingan agar selain perbandingan kesetaraan sederhana, dan itu adalah generik. Dengan mengimplementasikan Comparable, sebuah kelas menunjukkan bahwa instansnya memiliki urutan alami .

Java Efektif, Edisi Kedua : Joshua Bloch. Butir 12, Halaman 62. Elips menghapus referensi ke bab lain dan contoh kode.

Untuk kasus di mana Anda tidak ingin memaksakan sebuah memesan pada non Comparablekelas yang tidak memiliki memesan alami, Anda selalu dapat menyediakan Comparatorcontoh untuk bantuan semacam itu.


3
Bahkan ada yang lebih menyenangkan ketika Anda mulai berpikir tentang compareTo dengan Exception (yang bukan kelas abstrak dan karenanya akan mengimplementasikannya yang berarti aNullPointerException.compareTo (anUnsupportedFlavorException) akan memiliki ... makna?

10
semua objek bisa diperiksa kesetaraannya di Java ya, tapi secara umum tidak. Ada beberapa contoh objek di mana perbandingan kesetaraan tidak masuk akal (bahkan referensi referensi kesetaraan) - misalnya lajang. Mungkin ada antarmuka (kelas abstrak) seperti ValueEquality dan ReferenceEquality. Bahkan mungkin bukan ide yang buruk ...
qbd

5
"Semua objek dapat diperiksa untuk kesetaraan. Jika tidak ada yang lain, seseorang dapat melihat apakah dua objek ada di lokasi yang sama dalam memori (referensi persamaan)." - Karena kita memiliki ==untuk yang terakhir, ini memiliki cincin kosong untuk itu. Mengabaikan standar redundan, orang dapat menemukan alasan yang sah untuk tidak menganggap equalssemua kelas, karena tidak semua tipe dapat mendukung relasi ekivalensi.
Raphael

3
Dua contoh jenis di mana tidak masuk akal untuk mendefinisikan kesetaraan: aliran (misalnya daftar malas berpotensi tak terbatas atau angka presisi tak terbatas) dan fungsi. Yang pertama memiliki masalah yang membangun kesetaraan mungkin memerlukan membandingkan tanpa batas. Memutuskan apakah dua fungsi sama tidak dapat diputuskan. Bertanya apakah ada dua contoh dari jenis ini yang ada di lokasi memori yang sama adalah 1) tidak terlalu berguna dan 2) memungkinkan klien untuk menulis kode yang sensitif terhadap apa yang seharusnya menjadi rincian implementasi. Hari ini saya dapat memberikan Anda sebuah contoh baru dari daftar tak terbatas yang sama setiap kali Anda bertanya, besok saya dapat memo itu.
Doval

6
@Snowman Fakta bahwa itu tidak berguna dikombinasikan dengan fakta yang mengekspos detail implementasi cukup alasan untuk tidak mengizinkannya. Cukup banyak setiap kelas "berbasis nilai" di Java 8 memiliki beberapa boilerplate yang mengatakan "Kami tidak bertanggung jawab atas apa yang terjadi jika Anda menggunakan ==" karena bagaimana kelas-kelas tersebut dipakai adalah detail implementasi tetapi bahasa membuatnya mustahil untuk disembunyikan. Anda bisa mengatakan bahwa siapa pun yang membandingkan dua Integers dengan referensi adalah idiot, tetapi membiarkan perbandingan untuk memulai adalah masih bodoh.
Doval

8

The JLS §4.3.2 mendefinisikan classobjek dengan cara berikut:

4.3.2. Objek Kelas

Kelas Objectadalah superclass (§8.1.4) dari semua kelas lainnya.

Semua tipe kelas dan array mewarisi (§8.4.8) metode kelas Object , yang dirangkum sebagai berikut:

  • Metode clone ini digunakan untuk membuat duplikat objek.

  • Metode equals mendefinisikan gagasan tentang kesetaraan objek, yang didasarkan pada nilai, bukan referensi, perbandingan.

  • Metode finalize ini dijalankan tepat sebelum objek dihancurkan (§12.6).

  • Metode getClass mengembalikan objek Kelas yang mewakili kelas objek.

  • Sebuah Classobjek ada untuk setiap jenis referensi. Ini dapat digunakan, misalnya, untuk menemukan nama kelas yang sepenuhnya memenuhi syarat, anggotanya, superclass langsungnya, dan antarmuka apa pun yang diimplementasikan.

    Jenis ekspresi pemanggilan metode getClassadalah di Class<? extends |T|>mana Tkelas atau antarmuka dicari (§15.12.1) untuk getClass.

    Metode kelas yang dideklarasikan synchronized(§8.4.3.6) menyinkronkan pada monitor yang terkait dengan objek Kelas kelas.

  • Metode hashCodeini sangat berguna, sama dengan metode yang sama, dalam tagar seperti java.util.Hashmap.

  • Metode wait,, notifydan notifyAlldigunakan dalam pemrograman bersamaan menggunakan utas (§17.2).

  • Metode toStringmengembalikan representasi String objek.

Jadi, itu sebabnya equalsada di Objecttetapi compareTodalam antarmuka yang terpisah. Saya berspekulasi bahwa mereka ingin tetap Objectseminimal mungkin. Mereka mungkin mengira bahwa hampir semua Objects akan perlu equalsdan hashCode(yang sebenarnya hanyalah bentuk pengujian kesetaraan) tetapi tidak semua objek perlu memiliki konsep pemesanan , yang compareTodigunakan untuk apa.


Saya kira secara teoritis bisa ada antarmuka Equitable<T>tetapi jika Objectdiimplementasikan, maka setiap kelas akan menjadi Equitable<Object>. Pada titik itu, apakah ada perbedaan? Efeknya tidak juga, dalam kompleksitas ya.
Kapten Man

1
@ Kapten Man Dalam. Net, objectmemiliki Equals(object), seperti di Jawa, tetapi ada juga IEquatable<T>antarmuka. Meskipun alasan utama keberadaannya adalah untuk menghindari tinju ketika Tadalah tipe nilai, yang tidak mungkin di Jawa.
svick

kode hash bukan bentuk pengujian kesetaraan, karena ada tabrakan hash. jika A dan B sama, mereka memiliki kode hash yang sama, tetapi jika A dan B memiliki kode hash yang sama, ini tidak berarti mereka sama!
Josef

sebenarnya, jawaban Anda akan sangat diuntungkan dari beralih ke JLS yang lebih lama ( titanium.cs.berkeley.edu/doc/java-langspec-1.0.pdf ) - ia memiliki penawaran yang jauh lebih baik tentang mengapa equalsdinyatakan Objectsecara langsung: The methods equals and hashCode are declared for the benefit of hashtables such as java.util.Hashtable (§21.7)- karena desain Java kompatibel dengan mundur, pilihan desain Java 1.0 adalah alasan sebenarnya untuk equalskeberadaannya.
vaxquis

karena hasil edit yang saya usulkan kemungkinan akan ditolak karena "terlalu drastis", jika Anda ingin hanya Ctrl + C / Ctrl + V hal-hal yang relevan ke dalam jawaban Anda: pastebin.com/8c4EpLRX
vaxquis

2

Selain jawaban Snowman yang sangat baik, ingatlah bahwa Comparableitu telah menjadi antarmuka umum untuk waktu yang lama. Tipe tidak diimplementasikan compareTo(object), ia mengimplementasikan di compareTo(T)mana Tjenisnya sendiri. Ini tidak dapat diimplementasikan pada object, karena objecttidak tahu kelas yang akan diturunkan darinya.

objectbisa mendefinisikan suatu compareTo(object)metode, tetapi ini akan memungkinkan bukan hanya apa yang Snowman tunjukkan, perbandingan antara dua ArrayList<T>s atau antara dua Threads, tetapi bahkan perbandingan antara a ArrayList<T>dan a Thread. Itu bahkan lebih tidak masuk akal.


0

Misalkan saya memiliki dua referensi objek: X mengidentifikasi contoh Stringmemegang konten "George"; Y mengidentifikasi contoh Pointmemegang koordinat [12,34]. Pertimbangkan dua pertanyaan berikut:

  • Apakah X dan Y mengidentifikasi objek yang setara?

  • Haruskah X mengurutkan sebelum, sesudah, atau setara dengan Y?

Fakta bahwa X dan Y mengidentifikasi contoh tipe yang tidak terkait tidak menimbulkan masalah ketika mempertimbangkan pertanyaan pertama. Objek hanya dapat dianggap setara jika tipenya memiliki basis umum yang mendefinisikannya setara; sejak StringdanPoint tidak memiliki basis seperti itu (satu-satunya jenis basis umum mereka menganggap semua objek yang berbeda sebagai tidak setara) jawabannya hanyalah "tidak".

Namun, fakta bahwa tipe-tipe itu tidak berhubungan, menimbulkan masalah besar terkait dengan pertanyaan kedua. Beberapa jenis mendefinisikan hubungan pemesanan di antara instans mereka, dan beberapa relasi pemesanan bahkan meluas ke beberapa tipe [mis. Akan mungkin untuk BigIntegerdan BigDecimaluntuk menentukan metode perbandingan yang akan memungkinkan instance dari kedua tipe untuk diurutkan relatif terhadap instance yang lain], tetapi tidak mungkin secara umum untuk mengambil dua contoh arbitrer dan bertanya "Haruskah X mengurutkan sebelum, setelah, atau setara dengan Y" dan mendapatkan total pemesanan. Mungkin saja untuk bertanya "Haruskah X menyortir sebelum, sesudah, setara, atau tidak dibuka sehubungan dengan Y" jika objek diminta untuk melaporkan pemesanan yang konsisten meskipun tidak totalsatu, tetapi sebagian besar algoritma pengurutan membutuhkan pemesanan total. Jadi, bahkan jika semua objek dapat mengimplementasikan compareTometode jika "unranked" adalah pengembalian yang valid, metode seperti itu tidak akan cukup berguna untuk membenarkan keberadaannya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.