Pendahuluan: Ada banyak hal baru yang ditambahkan setelah Java 8. Saya menemukan beberapa informasi yang relevan secara online. Setelah Hashmap dilecehkan, saya memutuskan untuk memilah pengetahuan yang relevan untuk diri saya sendiri. Artikel ini untuk referensi dalam gambar dan beberapa konten: http://www.vevb.com/article/80446.htm
Struktur penyimpanan hashmap ditunjukkan pada gambar: jika ada lebih dari 8 node pada ember, struktur penyimpanan adalah pohon merah dan hitam, dan kurang dari 8 adalah daftar terkait satu arah.
1: Beberapa sifat hashmap
HashMap kelas publik <k, v> memperluas abstrak abstrak <k, v> mengimplementasikan peta <k, v>, kloning, serializable {private static final long serialVersionUid = 362498820763181265L; // kapasitas awal/ Kapasitas awal/ static/ stocatic final int default_initial_capacity = 1 <4 Kapasitas awal/ Kapasitas awal/ statatic final 16static Int default_initial_capacity = 1 prapasticy = 4; Kapasitas awal 4; 16Satic Int Default_initial_capacity = 1. 30; // Faktor pengisian default (versi sebelumnya juga disebut faktor beban) statis float statis default_load_factor = 0,75f; // Ini adalah ambang batas. Ketika jumlah daftar tertaut pada ember lebih besar dari nilai ini, itu akan dikonversi menjadi pohon merah dan hitam. Kode metode put statis int static int treeify_threshold = 8; // juga ambang batas. Ketika jumlah daftar yang ditautkan pada ember kurang dari nilai ini, pohon dikonversi ke daftar tertaut statis statis intreify_threshold = 6; // Dikatakan dalam Kode Sumber KOMENTAR bahwa itu adalah: kapasitas minimum dari pohon itu adalah setidaknya 4 x Treeify_threshold = 32. Kemudian untuk menghindari (Putar Ulang dan Pohon Pohon) yang ditetapkan oleh Treeify. Array elemen disimpan, selalu kelipatan dari 2 simpul transien <k, v> [] tabel; set transien <map.entry <k, v >> entri; // jumlah elemen yang disimpan, perhatikan bahwa ini tidak sama dengan panjang array. Ukuran int transien; // penghitung untuk setiap ekspansi dan perubahan struktur peta adalah transien int modcount; // Nilai kritis diperluas ketika ukuran aktual (kapasitas * faktor pengisian) melebihi nilai kritis, kapasitas diperluas intreshold;2: Metode Konstruksi Hashmap
// Konstruktor Untuk menentukan kapasitas awal dan faktor pengisian hashmap publik (int initialcapacity, float loadfactor) {// kapasitas awal yang ditentukan adalah non-negatif jika (kapasitas awal <0) melempar baru ilegalargumentException (kapasitas awal ilegal: +kapasitas awal);// jika kapasitas awal yang ditentukan lebih besar dari kapasitas maksimum, ke kapasitas maksimum, ke kapasitas maximumity); Maximum_capacity) InitialCapacity = maximum_capacity; // Rasio pengisian adalah positif jika (loadfactor <= 0 || float.isnan (loadfactor)) melempar baru ilegalargumentException (faktor beban ilegal: +loadfactor); this.loadFactor = loadFactor; // Setelah menentukan kapasitas, metode TablessizeFor menghitung nilai kritis. Jika nilainya terlampaui saat menempatkan data, itu akan berkembang. Nilainya jelas merupakan kelipatan 2.// Kapasitas awal yang ditentukan belum disimpan, dan hanya digunakan untuk menghasilkan nilai kritis this.threshold = TablesizeFor (InitialCapacity);} // Metode ini memastikan bahwa ia selalu mengembalikan nilai yang lebih besar dari CAP dan kelipatan 2. misalnya, lewat 999 Mengembalikan 1024Ssize Tables yang lebih tinggi (misalnya) (misalnya, tidak ada. Di sebelah kanan n | = n >>> 1; n | = n >>> 2; n | = n >>> 4; n | = n >>> 8; n | = n >>> 16; // pengembalian operator trigonometri yang bersarang (n <0)? 1: (n> = maximum_capacity)? Maximum_capacity: n + 1;} // konstruktor 2public hashmap (int initialcapacity) {this (initialcapacity, default_load_factor);} // konstruktor 3public hashmap () {this.loadfactor = default_load_factor; // Semua bidang lainnya default}3: Tentukan posisi elemen dalam array saat mendapatkan dan menempatkan
hash int static final (kunci objek) {int h; return (key == null)? 0: (h = key.hashCode ()) ^ (h >>> 16);}Untuk menentukan lokasinya
Langkah pertama: Hal pertama adalah menghitung kode hash kunci, yang merupakan nomor tipe int. Komentar Kode Sumber H >>> berikut mengatakan: Untuk menghindari tabrakan hash, posisi tinggi tersebar ke posisi rendah, yang dibuat setelah memperhitungkan berbagai faktor seperti kecepatan dan kinerja.
Langkah 2: h adalah kode hash, panjang adalah panjang array node [] di atas, lakukan operasi yang sama h & (panjang-1). Karena panjang adalah kelipatan 2 -1, kode binernya adalah 1 dan hasil 1 dengan angka lain di atasnya mungkin 0 atau 1, sehingga dapat memastikan keseragaman setelah operasi. Artinya, metode hash memastikan keseragaman hasil, yang sangat penting dan akan sangat mempengaruhi put dan mendapatkan kinerja hashmap. Lihat gambar berikut untuk perbandingan:
Gambar 3.1 adalah hasil hash asimetris
Gambar 3.2 adalah hasil hash seimbang
Tidak ada banyak data dalam dua grafik ini. Jika daftar yang ditautkan lebih dari 8, itu akan dikonversi menjadi pohon merah dan hitam. Akan lebih jelas pada waktu itu. JDK8 selalu menjadi daftar yang ditautkan sebelumnya. Kompleksitas kueri daftar yang ditautkan adalah O (n) dan kompleksitas pohon merah dan hitam karena karakteristik mereka sendiri adalah O (log (n)). Jika hasil hash tidak rata, itu akan sangat mempengaruhi kompleksitas operasi. Ada <a href = "http://blog.chinaunix.net/uid-26575352-id-3061918.html"> Blog Pengetahuan Dasar Pohon Merah dan Hitam </a> Ada contoh lain secara online untuk memverifikasi: Objek kustom digunakan untuk membuat tombol, dan menyesuaikan metode yang telah menodai () Metode That That Helshcode () Metode itu.
kelas publik mutableKeyTest {public static void main (string args []) {class mykey {integer i; public void seti (integer i) {this.i = i;} public mykey (integer i) {this.i = i;}@overridepublic int hashcode () {/ if 1// i jika 1//@overridepublic int hashcode () {/ if 1// if 1//}@overridepublic int hashcode () {/ if 1/ ife 1//}@overridepublic int hashcode () {/ if 1/ ife 1//@overridepublic int hashcode () {/ if 1/ ife Harus diimplementasikan @Overridepublic Boolean Equals (objek obj) {if (instance Obj dari mykey) {return i.equals ((((mykey) obj) .i);} else {return false;}} // my machine configuration tidak tinggi. Jika 25.000 normal untuk 27ms, Anda dapat mencoba 25 juta. Jika hashcy hashc saya tidak tinggi. Jika 25.000 normal untuk 27ms, Anda dapat mencoba 25 juta. Jika hashcy hashc saya tidak akan tinggi. Jika 25000 adalah normal untuk 27ms, Anda dapat mencoba 25 juta. Jika hashc saya hashc tidak ada. = hashmap baru <> (25000,1); tanggal mulai = tanggal baru (); untuk (int i = 0; i <20000; i ++) {map.put (mykey baru (i), "tes" + i);} tanggal akhir = tanggal baru (); System.out.println ("waktu (ms)" + (end.gettime () - begin.4: Dapatkan metode
public v get (tombol objek) {node <k, v> e; return (e = getNode (hash (tombol), key)) == null? null: e.value;} node akhir <k, v> getNode (int hash, tombol objek) {node <k, v> [] tab; Node <k, v> pertama, e; int n; K k; // hash & (length -1) Dapatkan posisi root dari pohon merah dan hitam atau header dari daftar yang ditautkan if ((tab = tabel)! = Null && (n = tab.length)> 0 && (pertama = tab [(n - 1) & hash])! = Null) {if (first.hash == hash & & hash/ hash]/ nol first) {if (first.hash == hash & & hash/ hash SELALU key.equals (k)))) kembali terlebih dahulu; if ((e = first.next)! = null) {// Jika itu adalah pohon, kompleksitas melintasi pohon merah dan hitam adalah o (log (n)) untuk mendapatkan nilai simpul jika (haveNODE (hash, hash. hash && ((k = e.key) == key || (key! = null && key.equals (k)))) return e;} while ((e = e.next)! = null);}} return null;}5: Letakkan metode, saat dimasukkan, cari ember menurut H & (panjang 1) dan kemudian lihat apakah itu pohon merah dan hitam atau daftar yang ditautkan dan putval
public v put (key k, nilai v) {return putval (hash (kunci), kunci, nilai, false, true);} final v putval (int hash, k kunci, nilai v, boolean justanifabsent, boolean eVict) {node <k, v> [] tab; Node <k, v> p; int n, i; // Jika tab kosong atau panjangnya 0, memori dialokasikan mengubah ukuran () if ((tab = tabel) == null || (n = tab.length) == 0) n = (tab = ubah ukuran ()). Panjang; // (n - 1) & hash menemukan posisi put. Jika kosong, putif langsung ((p = tab [i = (n - 1) & hash]) == null) tab [i] = newNode (hash, kunci, nilai, null); else {node <k, v> e; K k; // Nilai hash dari simpul pertama adalah sama, dan nilai kunci sama dengan kunci insert if (p.hash == hash && ((k = p.key) == key || (kunci! = Null && key.equals (k))) e = p; lain jika (p contoh dari treenode) // Metode put red dan black. Setelah Putval, Anda harus melintasi seluruh pohon. Bila perlu, modifikasi nilai untuk memastikan karakteristik pohon merah dan hitam e = ((treenode <k, v>) p) .puttreeval (ini, tab, hash, kunci, nilai); else {// daftar tertaut (int bincount = 0;; ++ bincount) {if ((e = p.next) == null) {{{{{if yang sama) {if (e = p.next) == null) {{null) {{{e yang sama dengan naPOOD) {if (E = p.next) == null) {null) { end of the table, then create a new node p.next = newNode(hash, key, value, null);// After adding a new node, if the number of nodes reaches the threshold, convert the linked list to a red and black tree if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}// Allow empty key to empty valueif (e.hash == hash && ((k = e.key) == key || (key! = null && key.equals (k)))) break; p = e;}} // Perbarui nilai simpul dengan nilai hash yang sama dan nilai kunci jika (e! = null) {// pemetaan yang ada untuk keyv oldvalue = e.value; hanya (! Nilai; sore hari (e); kembalikan oldValue;}} ++ modcount; if (++ size> ambang batas) ukuran (); sore -aPryinsertion (eVict); return null;}6: Metode Ukuran
Node akhir <k, v> [] mengubah ukuran () {node <k, v> [] oldtab = tabel; int oldcap = (oldtab == null)? 0: oldtab.length; int oldthr = threshold; int newcap, newThr = 0; if (oldcap> 0) {if (oldcap> = maximum_capacity) {threshold = integer.max_value; return oldtab;} // Kalimat ini lebih penting, itu dapat dilihat bahwa setiap ekspansi; && oldcap> = default_initial_capacity) newThr = OldThRT << 1; // ambang ganda} lain jika (oldthr> 0) // kapasitas awal ditempatkan di thresholdNewCap = oldhrhThr; else {// nol ambang batas awal yang menandakan menggunakan defaultsnewcap = default_initial_capacity; newThr = (int) (default_load_factor * default_initial_capacity = newTr =) (default o need = = {new = need = ne Newthr = ne Newthr = ne Newthr = ne Newthr = * LoadFactor; newThR = (newcap <maximum_capacity && ft <(float) maximum_capacity? (int) ft: integer.max_value);} threshold = newThr; @suppresswarnings ({"rawtypes", "noCecked"}) <K, v> nodab, "noelpes", "noCecked"}) <K, v> noodeD (noelpes "," noCecked "}) <k, v> nodab," noelpes "," noCECCED "}) <K, v> nODAP = NODE (noWAB," Node [newcap]; table = newtab; if (oldtab! = Null) {for (int j = 0; j <oldcap; ++ j) {node <k, v> e; if ((e = oldtab [j])! = Null) {oldtab [j] = null; if if (e.eNext == null) null) {haHa [j] = null; if if (e.eNext == null) null) null) [haPh [j] = null; if (e.next == null) null) null) [haPh [j] = null; if if (e.eNext == null) null) null) [haPab [j] TreeNode)((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { // preserve orderNode<K,V> loHead = null, loTail = null;Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;do {next = e.next;if ((e.hash & oldCap) == 0) {if (LOTAIL == NULL) loHead = e; elselotail.next = e; lotail = e;} else {if (hitail == null) hiHead = e; elshitail.next = e; hitail = e;}} while (e = next) = null); if (ifeil! = null) {lotaail. null) {hitail.next = null; newtab [j + oldcap] = hiMeHead;}}}}} return newtab;}Di atas adalah pengetahuan yang relevan tentang analisis prinsip implementasi java8 hashmap yang diperkenalkan kepada Anda oleh editor. Saya harap ini akan membantu Anda!