Apa perbedaan antara peta-peta berikut yang saya buat (dalam pertanyaan lain, orang-orang menjawab menggunakannya secara bergantian dan saya bertanya-tanya apakah / bagaimana mereka berbeda):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
java
dictionary
hashmap
Tony Stark
sumber
sumber
Jawaban:
Tidak ada perbedaan antara objek; Anda memiliki
HashMap<String, Object>
dalam kedua kasus. Ada perbedaan dalam antarmuka yang Anda miliki ke objek. Dalam kasus pertama, antarmuka adalahHashMap<String, Object>
, sedangkan yang kedua adalahMap<String, Object>
. Tetapi objek yang mendasarinya adalah sama.Keuntungan menggunakan
Map<String, Object>
adalah Anda dapat mengubah objek yang mendasarinya menjadi jenis peta yang berbeda tanpa memutus kontrak Anda dengan kode apa pun yang menggunakannya. Jika Anda menyatakannya sebagaiHashMap<String, Object>
, Anda harus mengubah kontrak Anda jika Anda ingin mengubah implementasi yang mendasarinya.Contoh: Katakanlah saya menulis kelas ini:
Kelas memiliki beberapa peta internal objek string-> yang dibagikan (melalui metode accessor) dengan subclass. Katakanlah saya menulisnya dengan
HashMap
s karena saya pikir itu adalah struktur yang tepat untuk digunakan ketika menulis kelas.Kemudian, Mary menulis kode subkelasnya. Dia memiliki sesuatu yang perlu dia lakukan dengan keduanya
things
danmoreThings
, jadi secara alami dia menempatkan itu dalam metode umum, dan dia menggunakan tipe yang sama yang saya gunakan padagetThings
/getMoreThings
ketika mendefinisikan metodenya:Kemudian, saya memutuskan bahwa sebenarnya, lebih baik jika saya menggunakan
TreeMap
daripadaHashMap
diFoo
. Saya memperbaruiFoo
, berubahHashMap
menjadiTreeMap
. Sekarang,SpecialFoo
tidak mengkompilasi lagi, karena saya telah melanggar kontrak:Foo
dulu mengatakan itu diberikanHashMap
, tetapi sekarang menyediakan ituTreeMaps
sebagai gantinya. Jadi kita harus memperbaikinyaSpecialFoo
sekarang (dan hal semacam ini dapat mengacak basis kode).Kecuali saya memiliki alasan yang sangat bagus untuk berbagi bahwa implementasi saya menggunakan
HashMap
(dan itu memang terjadi), apa yang seharusnya saya lakukan adalah menyatakangetThings
dangetMoreThings
hanya kembaliMap<String, Object>
tanpa menjadi lebih spesifik dari itu. Bahkan, kecuali alasan yang baik untuk melakukan sesuatu yang lain, bahkan di dalamFoo
saya mungkin harus menyatakanthings
danmoreThings
sebagaiMap
, bukanHashMap
/TreeMap
:Perhatikan bagaimana saya sekarang menggunakan di
Map<String, Object>
mana saja saya bisa, hanya spesifik ketika saya membuat objek yang sebenarnya.Jika saya melakukan itu, maka Mary akan melakukan ini:
... dan mengubah
Foo
tidak akan membuatSpecialFoo
kompilasi berhenti.Antarmuka (dan kelas dasar) memungkinkan kami mengungkapkan sebanyak yang diperlukan , menjaga fleksibilitas kami di bawah penutup untuk membuat perubahan yang sesuai. Secara umum, kami ingin agar referensi kami sedasar mungkin. Jika kita tidak perlu tahu itu adalah
HashMap
, sebut saja aMap
.Ini bukan aturan buta, tetapi secara umum, pengkodean ke antarmuka paling umum akan menjadi kurang rapuh daripada pengkodean untuk sesuatu yang lebih spesifik. Jika saya ingat itu, saya tidak akan membuat
Foo
yang membuat Mary gagalSpecialFoo
. Jika Mary ingat itu, maka meskipun aku mengacauFoo
, dia akan mendeklarasikan metode pribadinyaMap
sebagai gantiHashMap
dan danFoo
kontrakku yang berubah tidak akan memengaruhi kode etiknya.Terkadang Anda tidak bisa melakukan itu, terkadang Anda harus spesifik. Tetapi kecuali Anda memiliki alasan untuk itu, berbuat salah menuju antarmuka yang paling tidak spesifik.
sumber
Peta adalah antarmuka yang mengimplementasikan HashMap . Perbedaannya adalah bahwa dalam implementasi kedua referensi Anda ke HashMap hanya akan memungkinkan penggunaan fungsi yang didefinisikan dalam antarmuka Peta, sedangkan yang pertama akan memungkinkan penggunaan fungsi publik apa pun di HashMap (yang mencakup antarmuka Peta).
Mungkin akan lebih masuk akal jika Anda membaca tutorial antarmuka Sun.
sumber
Peta memiliki implementasi sebagai berikut:
HashMap
Map m = new HashMap();
LinkedHashMap
Map m = new LinkedHashMap();
Peta Pohon
Map m = new TreeMap();
WeakHashMap
Map m = new WeakHashMap();
Misalkan Anda telah membuat satu metode (ini hanya kodesemu).
Misalkan perubahan persyaratan proyek Anda:
HashMap
.HashMap
keLinkedHashMap
.LinkedHashMap
keTreeMap
.Jika metode Anda mengembalikan kelas tertentu dan bukan sesuatu yang mengimplementasikan
Map
antarmuka, Anda harus mengubah jenisgetMap()
metode kembali setiap kali.Tetapi jika Anda menggunakan fitur polimorfisme Java, dan bukannya mengembalikan kelas-kelas tertentu, gunakan antarmuka
Map
, itu meningkatkan penggunaan kembali kode dan mengurangi dampak perubahan persyaratan.sumber
Saya hanya akan melakukan ini sebagai komentar pada jawaban yang diterima tetapi terlalu funky (saya benci tidak memiliki jeda baris)
Tepat - dan Anda selalu ingin menggunakan antarmuka paling umum yang Anda bisa. Pertimbangkan ArrayList vs LinkedList. Perbedaan besar dalam cara Anda menggunakannya, tetapi jika Anda menggunakan "Daftar" Anda dapat beralih di antara mereka dengan mudah.
Bahkan, Anda dapat mengganti sisi kanan penginisialisasi dengan pernyataan yang lebih dinamis. Bagaimana dengan sesuatu yang seperti ini:
Dengan cara ini jika Anda akan mengisi koleksi dengan semacam penyisipan, Anda akan menggunakan daftar tertaut (semacam penyisipan ke dalam daftar array adalah kriminal.) Tetapi jika Anda tidak perlu menyimpannya diurutkan dan hanya menambahkan, Anda menggunakan ArrayList (Lebih efisien untuk operasi lain).
Ini adalah peregangan yang cukup besar di sini karena koleksi bukan contoh terbaik, tetapi dalam desain OO salah satu konsep paling penting adalah menggunakan fasad antarmuka untuk mengakses objek yang berbeda dengan kode yang sama persis.
Edit menanggapi komentar:
Adapun komentar peta Anda di bawah ini, Ya menggunakan antarmuka "Peta" membatasi Anda hanya pada metode-metode itu kecuali Anda mengembalikan koleksi dari Peta ke HashMap (yang SEPENUHNYA mengalahkan tujuannya).
Seringkali yang akan Anda lakukan adalah membuat objek dan mengisinya dengan menggunakan tipe spesifiknya (HashMap), dalam beberapa jenis metode "buat" atau "inisialisasi", tetapi metode itu akan mengembalikan "Peta" yang tidak perlu dimanipulasi sebagai HashMap lagi.
Jika Anda harus melakukannya, Anda mungkin menggunakan antarmuka yang salah atau kode Anda tidak terstruktur dengan baik. Perhatikan bahwa dapat diterima jika satu bagian dari kode Anda memperlakukannya sebagai "HashMap" sementara yang lain memperlakukannya sebagai "Peta", tetapi ini akan mengalir "turun". agar kamu tidak pernah casting.
Perhatikan juga aspek peran yang semi-rapi yang ditunjukkan oleh antarmuka. LinkedList membuat stack atau antrian yang baik, ArrayList membuat stack yang bagus tetapi antrian yang mengerikan (sekali lagi, sebuah penghapusan akan menyebabkan pergeseran seluruh daftar) sehingga LinkedList mengimplementasikan antarmuka antrian, ArrayList tidak.
sumber
Seperti dicatat oleh TJ Crowder dan Adamski, satu referensi adalah antarmuka, yang lain untuk implementasi spesifik antarmuka. Menurut Joshua Block, Anda harus selalu berusaha kode ke antarmuka, untuk memungkinkan Anda menangani perubahan implementasi yang lebih baik - yaitu jika HashMap tiba-tiba tidak ideal untuk solusi Anda dan Anda perlu mengubah implementasi peta, Anda masih bisa menggunakan Peta antarmuka, dan ubah jenis instantiation.
sumber
Dalam contoh kedua Anda, referensi "peta" adalah tipe
Map
, yang merupakan antarmuka yang diimplementasikan olehHashMap
(dan jenis lain dariMap
). Antarmuka ini adalah kontrak yang mengatakan bahwa objek memetakan nilai-nilai dan mendukung berbagai operasi (misalnyaput
,get
). Ia mengatakan apa-apa tentang pelaksanaan dariMap
(dalam hal iniHashMap
).Pendekatan kedua umumnya lebih disukai karena Anda biasanya tidak ingin mengekspos implementasi peta spesifik untuk metode yang menggunakan
Map
atau melalui definisi API.sumber
Peta adalah tipe peta statis , sedangkan HashMap adalah tipe peta dinamis . Ini berarti bahwa kompiler akan memperlakukan objek peta Anda sebagai salah satu dari tipe Peta, meskipun saat runtime, ia mungkin menunjuk ke subtipe apa pun darinya.
Praktik pemrograman terhadap antarmuka dan bukan implementasi ini memiliki manfaat tambahan dengan tetap fleksibel: Misalnya, Anda dapat mengganti tipe dinamis peta saat runtime, asalkan itu adalah subtipe Peta (misalnya LinkedHashMap), dan mengubah perilaku peta pada lalat.
Aturan praktis yang baik adalah untuk tetap seabstrak mungkin pada tingkat API: Jika misalnya metode yang Anda pemrograman harus bekerja pada peta, maka itu cukup untuk mendeklarasikan parameter sebagai Peta alih-alih yang lebih ketat (karena kurang abstrak) tipe HashMap . Dengan begitu, konsumen API Anda bisa fleksibel tentang jenis implementasi Peta yang ingin mereka sampaikan ke metode Anda.
sumber
Menambah jawaban pilihan teratas dan banyak yang di atas menekankan "lebih umum, lebih baik", saya ingin menggali sedikit lebih banyak.
Map
adalah struktur kontrak sementaraHashMap
merupakan implementasi yang menyediakan metode sendiri untuk menghadapi berbagai masalah nyata: bagaimana menghitung indeks, apa kapasitasnya dan bagaimana meningkatkannya, bagaimana memasukkannya, bagaimana membuat indeksnya unik, dll.Mari kita lihat kode sumbernya:
Di
Map
kami memiliki metodecontainsKey(Object key)
:JavaDoc:
Ia membutuhkan implementasinya untuk mengimplementasikannya, tetapi "bagaimana caranya" adalah kebebasannya, hanya untuk memastikan ia kembali dengan benar.
Dalam
HashMap
:Ternyata yang
HashMap
menggunakan kode hash untuk menguji apakah peta ini berisi kunci. Jadi itu memiliki manfaat dari algoritma hash.sumber
Anda membuat peta yang sama.
Tetapi Anda dapat mengisi perbedaannya saat menggunakannya. Dengan case pertama Anda akan dapat menggunakan metode HashMap khusus (tapi saya tidak ingat ada orang yang benar-benar berguna), dan Anda akan dapat meneruskannya sebagai parameter HashMap:
sumber
Peta adalah antarmuka dan Hashmap adalah kelas yang mengimplementasikan Antarmuka Peta
sumber
Peta adalah Antarmuka dan Hashmap adalah kelas yang mengimplementasikannya.
Jadi dalam implementasi ini Anda membuat objek yang sama
sumber
HashMap adalah implementasi dari Map sehingga cukup sama tetapi memiliki metode "clone ()" seperti yang saya lihat di panduan referensi))
sumber
Pertama-tama
Map
adalah sebuah antarmuka memiliki implementasi yang berbeda seperti -HashMap
,TreeHashMap
,LinkedHashMap
dll Antarmuka bekerja seperti kelas super untuk kelas pelaksana. Jadi menurut aturan OOP setiap kelas konkret yang mengimplementasikanMap
adalahMap
juga. Itu berarti kita dapat menetapkan / menempatkanHashMap
variabel tipe apa pun keMap
variabel tipe tanpa tipe casting apa pun.Dalam hal ini kita dapat menetapkan
map1
untukmap2
tanpa pengecoran atau kalah data -sumber