Saya terkejut dengan fakta bahwa Map<?,?>
itu bukan Collection<?>
.
Saya pikir itu akan sangat masuk akal jika dinyatakan seperti itu:
public interface Map<K,V> extends Collection<Map.Entry<K,V>>
Lagi pula, a Map<K,V>
adalah koleksi Map.Entry<K,V>
, bukan?
Jadi apakah ada alasan bagus mengapa itu tidak diterapkan seperti itu?
Berkat Cletus untuk jawaban yang paling otoritatif, tapi aku masih bertanya-tanya mengapa, jika Anda sudah bisa melihat Map<K,V>
seperti Set<Map.Entries<K,V>>
(melalui entrySet()
), tidak hanya memperpanjang antarmuka yang sebaliknya.
Jika a
Map
adalah aCollection
, apa saja elemennya? Satu-satunya jawaban yang masuk akal adalah "Pasangan nilai kunci"
Persis, interface Map<K,V> extends Set<Map.Entry<K,V>>
pasti hebat!
tetapi ini memberikan
Map
abstraksi yang sangat terbatas (dan tidak terlalu berguna) .
Tetapi jika itu yang terjadi maka mengapa entrySet
ditentukan oleh antarmuka? Entah bagaimana itu harus berguna (dan saya pikir mudah untuk memperdebatkan posisi itu!).
Anda tidak bisa menanyakan nilai apa yang diberikan peta kunci, Anda juga tidak bisa menghapus entri untuk kunci yang diberikan tanpa mengetahui nilai apa yang dipetakannya.
Saya tidak mengatakan bahwa hanya itu yang ada untuk itu Map
! Itu bisa dan harus menyimpan semua metode lain (kecuali entrySet
, yang berlebihan sekarang)!
sumber
Jawaban:
Dari FAQ Desain Java Collections API :
Pembaruan: Saya pikir kutipan menjawab sebagian besar pertanyaan. Ada baiknya menekankan bagian tentang koleksi entri yang tidak menjadi abstraksi yang sangat berguna. Sebagai contoh:
akan memperbolehkan:
(dengan asumsi
entry()
metode yang membuatMap.Entry
instance)Map
s memerlukan kunci unik sehingga ini akan melanggar ini. Atau jika Anda memaksakan kunci unik padaSet
entri, itu tidak benar-benarSet
dalam arti umum. IniSet
dengan pembatasan lebih lanjut.Bisa dibilang Anda dapat mengatakan
equals()
/hashCode()
hubungan untukMap.Entry
itu murni pada kunci tetapi bahkan yang memiliki masalah. Lebih penting lagi, apakah itu benar-benar menambah nilai? Anda mungkin menemukan abstraksi ini rusak setelah Anda mulai melihat kasing sudut.Perlu dicatat bahwa
HashSet
sebenarnya diimplementasikan sebagaiHashMap
, bukan sebaliknya. Ini murni detail implementasi tetapi tetap menarik.Alasan utama untuk
entrySet()
ada adalah untuk menyederhanakan traversal sehingga Anda tidak perlu melintasi kunci dan kemudian melakukan pencarian kunci. Jangan menganggapnya sebagai bukti prima facie bahwa aMap
harus berupaSet
entri (imho).sumber
entrySet()
tidak mendukungremove
, sementara itu tidak mendukungadd
(mungkin melemparUnsupportedException
). Jadi saya mengerti maksud Anda, tapi sekali lagi, saya melihat poin OP juga .. (Pendapat saya sendiri seperti yang dinyatakan dalam jawaban saya sendiri ..)add
dapat ditangani seperti halnyaentrySet()
tampilan: biarkan beberapa operasi dan jangan biarkan yang lain. Respons alami, tentu saja, adalah "Apa yangSet
tidak mendukungadd
?" - yah, jika perilaku seperti itu dapat diterimaentrySet()
, lalu mengapa itu tidak dapat diterimathis
? Yang mengatakan, saya saya sebagian besar yakin sudah mengapa hal ini bukan ide yang bagus karena saya pernah berpikir, tapi saya masih berpikir itu layak perdebatan lebih lanjut, jika hanya untuk memperkaya pemahaman saya sendiri dari apa yang membuat desain yang baik API / OOP.Collection
memperpanjangMap
?Meskipun Anda sudah mendapatkan sejumlah jawaban yang menjawab pertanyaan Anda secara langsung, saya pikir mungkin berguna untuk mundur sedikit, dan melihat pertanyaan itu sedikit lebih umum. Yaitu, tidak untuk melihat secara khusus bagaimana perpustakaan Java terjadi untuk ditulis, dan melihat mengapa itu ditulis seperti itu.
Masalahnya di sini adalah bahwa pewarisan hanya memodelkan satu jenis kesamaan. Jika Anda memilih dua hal yang keduanya tampak "seperti koleksi", Anda mungkin dapat memilih 8 atau 10 kesamaan yang mereka miliki. Jika Anda memilih sepasang yang berbeda dari "koleksi-seperti" hal-hal, mereka akan juga 8 atau 10 kesamaan - tetapi mereka tidak akan menjadi sama 8 atau 10 hal sebagai pasangan pertama.
Jika Anda melihat selusin berbeda "koleksi-seperti" hal, hampir setiap satu dari mereka mungkin akan memiliki sesuatu seperti 8 atau 10 karakteristik yang sama dengan setidaknya satu satu lain - tetapi jika Anda melihat apa yang dibagikan di seluruh setiap satu dari mereka, Anda tidak punya apa-apa.
Ini adalah situasi di mana warisan (terutama warisan tunggal) tidak dapat dimodelkan dengan baik. Tidak ada garis pemisah yang bersih di antara yang benar-benar koleksi dan yang tidak - tetapi jika Anda ingin mendefinisikan kelas Koleksi yang bermakna, Anda terjebak dengan mengabaikan beberapa di antaranya. Jika Anda hanya meninggalkan beberapa di antaranya, kelas Collection Anda hanya akan dapat memberikan antarmuka yang jarang. Jika Anda meninggalkan lebih banyak, Anda akan dapat memberikan antarmuka yang lebih kaya.
Beberapa juga mengambil opsi untuk mengatakan: "jenis koleksi ini mendukung operasi X, tetapi Anda tidak diizinkan menggunakannya, dengan berasal dari kelas dasar yang mendefinisikan X, tetapi mencoba menggunakan kelas turunan 'X gagal (mis. , dengan melemparkan pengecualian).
Itu masih menyisakan satu masalah: hampir terlepas dari apa yang Anda tinggalkan dan yang Anda masukkan, Anda harus menarik garis keras antara apa kelas yang masuk dan apa yang keluar. Tidak peduli di mana Anda menggambar garis itu, Anda akan dibiarkan dengan pembagian yang jelas, agak artifisial, antara beberapa hal yang sangat mirip.
sumber
Saya kira mengapa itu subjektif.
Di C #, saya pikir
Dictionary
memperluas atau setidaknya mengimplementasikan koleksi:Di Pharo Smalltak juga:
Tetapi ada asimetri dengan beberapa metode. Misalnya,
collect:
akan mengambil asosiasi (setara dengan entri), sambildo:
mengambil nilai. Mereka menyediakan metode lainkeysAndValuesDo:
untuk mengulang kamus dengan entri.Add:
mengambil asosiasi, tetapiremove:
telah "ditekan":Jadi itu bisa dilakukan secara definitif, tetapi mengarah ke beberapa masalah lain mengenai hirarki kelas.
Apa yang lebih baik itu subjektif.
sumber
Jawaban cletus bagus, tapi saya ingin menambahkan pendekatan semantik. Untuk menggabungkan keduanya tidak masuk akal, pikirkan kasus Anda menambahkan pasangan kunci-nilai melalui antarmuka koleksi dan kunci sudah ada. Map-interface memungkinkan hanya satu nilai yang terkait dengan kunci. Tetapi jika Anda secara otomatis menghapus entri yang ada dengan kunci yang sama, koleksi memiliki setelah menambahkan ukuran yang sama seperti sebelumnya - sangat tak terduga untuk koleksi.
sumber
Set
kerjanya, danSet
apakah diimplementasikanCollection
.Koleksi Java rusak. Ada antarmuka yang hilang, yaitu Relation. Karenanya, Map extends Relation extends Set. Hubungan (juga disebut multi-peta) memiliki pasangan nama-nilai yang unik. Peta (alias "Fungsi"), memiliki nama unik (atau kunci) yang tentu saja memetakan ke nilai. Urutan memperpanjang Peta (di mana setiap tombol bilangan bulat> 0). Tas (atau multi-set) memperluas Peta (di mana setiap tombol adalah elemen dan nilai masing-masing adalah berapa kali elemen muncul dalam tas).
Struktur ini akan memungkinkan persimpangan, gabungan dll dari berbagai "koleksi". Karenanya, hierarki harus:
Sun / Oracle / Java ppl - lakukan dengan benar lain kali. Terima kasih.
sumber
Jika Anda melihat struktur data masing-masing, Anda dapat dengan mudah menebak alasannya
Map
bukan bagian dari ituCollection
. Masing-masingCollection
menyimpan nilai tunggal di mana sebagai pasanganMap
kunci menyimpan nilai. Jadi metode dalamCollection
antarmuka tidak kompatibel untukMap
antarmuka. Misalnya yangCollection
kita milikiadd(Object o)
. Apa yang akan menjadi implementasi diMap
. Tidak masuk akal untuk memiliki metode seperti itu diMap
. Sebaliknya, kami memilikiput(key,value)
metode dalamMap
.Argumen yang sama berlaku untuk
addAll()
,remove()
danremoveAll()
metode. Jadi alasan utama adalah perbedaan cara data disimpan diMap
danCollection
. Juga jika Anda ingatCollection
antarmuka yang diimplementasikanIterable
antarmuka yaitu setiap antarmuka dengan.iterator()
metode harus mengembalikan iterator yang harus memungkinkan kita untuk mengulangi nilai-nilai yang disimpan diCollection
. Sekarang apa yang akan dikembalikan dengan metode seperti ituMap
? Iterator kunci atau iterator nilai? Ini juga tidak masuk akal.Ada beberapa cara di mana kita dapat beralih pada kunci dan nilai yang disimpan dalam a
Map
dan itu adalah bagian dariCollection
kerangka kerja.sumber
There are ways in which we can iterate over keys and values stores in a Map and that is how it is a part of Collection framework.
Bisakah Anda menunjukkan contoh kode untuk ini?add(Object o)
akan menambahkanEntry<ClassA, ClassB>
objek. AMap
dapat dianggap sebagaiCollection of Tuples
Sebenarnya, jika iya
implements Map<K,V>, Set<Map.Entry<K,V>>
, maka saya cenderung setuju .. Sepertinya wajar saja. Tapi itu tidak bekerja dengan baik, bukan? Katakanlah kita punyaHashMap implements Map<K,V>, Set<Map.Entry<K,V>
,LinkedHashMap implements Map<K,V>, Set<Map.Entry<K,V>
dll ... itu semua baik, tetapi jika Anda punyaentrySet()
, tidak ada yang akan lupa untuk menerapkan metode itu, dan Anda dapat yakin bahwa Anda bisa mendapatkan entriSetiap Peta apa pun, sedangkan Anda tidak melakukannya jika Anda berharap bahwa implementor telah mengimplementasikan kedua antarmuka ...Alasan saya tidak ingin memiliki
interface Map<K,V> extends Set<Map.Entry<K,V>>
sederhana, karena akan ada lebih banyak metode. Lagi pula, mereka adalah hal yang berbeda, bukan? Juga sangat praktis, jika saya menekanmap.
IDE, saya tidak ingin melihat.remove(Object obj)
, dan.remove(Map.Entry<K,V> entry)
karena saya tidak dapat melakukanhit ctrl+space, r, return
dan menyelesaikannya.sumber
Map<K,V>
tidak boleh diperpanjangSet<Map.Entry<K,V>>
sejak:Map.Entry
dengan kunci yang sama untuk yang samaMap
, tetapiMap.Entry
s dengan kunci yang sama ke yang samaSet<Map.Entry>
.sumber
Lurus dan sederhana. Koleksi adalah antarmuka yang mengharapkan hanya satu Objek, sedangkan Peta membutuhkan Dua.
sumber