Vodič za LinkedHashMap u Javi

1. Pregled

U ovom ćemo članku istražiti internu provedbu LinkedHashMap razred. LinkedHashMap je uobičajena provedba Karta sučelje.

Ova konkretna provedba je podrazred HashMap i stoga dijeli temeljne blokove sustava HashMap provedba. Kao rezultat toga, toplo se preporučuje da to razriješite prije nego što nastavite s ovim člankom.

2. LinkedHashMap nasuprot HashMap

The LinkedHashMap razred je vrlo sličan HashMap u većini aspekata. Međutim, povezana hash karta temelji se i na hash tablici i na povezanom popisu kako bi se poboljšala funkcionalnost hash mape.

Održava dvostruko povezan popis koji prolazi kroz sve njegove unose uz osnovni niz zadane veličine 16.

Da bi se održao redoslijed elemenata, povezana hashmapa mijenja Karta.Ulaz razred HashMap dodavanjem pokazivača na sljedeći i prethodni unos:

statička klasa Entry proteže HashMap.Node {Entry before, after; Unos (int hash, K ključ, V vrijednost, Node next) {super (hash, ključ, vrijednost, sljedeći); }}

Primijetite da Ulazak klasa jednostavno dodaje dva pokazivača; prije i nakon koji mu omogućuju da se prikopča na povezani popis. Osim toga, koristi Ulazak klasa implementacija HashMap-a.

Na kraju, ne zaboravite da ovaj povezani popis definira redoslijed ponavljanja, koji je prema zadanim postavkama redoslijed umetanja elemenata (redoslijed umetanja).

3. Umetak-nalog LinkedHashMap

Pogledajmo povezanu instancu hash karte koja svoje unose poreda prema načinu na koji su umetnuti na kartu. Također jamči da će se ovaj redoslijed održavati tijekom životnog ciklusa karte:

@Test javna praznina givenLinkedHashMap_whenGetsOrderedKeyset_thenCorrect () {LinkedHashMap map = new LinkedHashMap (); map.put (1, null); map.put (2, null); map.put (3, null); map.put (4, null); map.put (5, null); Postavi tipke = map.keySet (); Integer [] arr = keys.toArray (novi Integer [0]); for (int i = 0; i <arr.length; i ++) {assertEquals (novi Integer (i + 1), arr [i]); }}

Ovdje jednostavno vršimo osnovni, nedvosmisleni test redoslijeda unosa na povezanoj hash mapi.

Možemo jamčiti da će ovaj test uvijek proći jer će se redoslijed umetanja uvijek održavati. Ne možemo dati isto jamstvo za HashMap.

Ovaj atribut može biti od velike prednosti u API-ju koji prima bilo koju kartu, izrađuje kopiju kojom se manipulira i vraća je pozivnom kodu. Ako klijent treba da se vraćena karta naruči na isti način prije pozivanja API-ja, tada je povezana povezana hashmapa.

Redoslijed umetanja neće utjecati ako se ključ ponovo umetne na kartu.

4. Pristup-nalog LinkedHashMap

LinkedHashMap pruža poseban konstruktor koji nam omogućuje da odredimo, između prilagođenog faktora opterećenja (LF) i početnog kapaciteta, drugačiji mehanizam / strategija naručivanja koji se naziva pristupni poredak:

Karta LinkedHashMap = nova LinkedHashMap (16, .75f, točno);

Prvi je parametar početni kapacitet, a slijedi faktor opterećenja i zadnji parametar je način naručivanja. Dakle, prolaskom pravi, uključili smo nalog za pristup, dok je zadani nalog za umetanje.

Ovaj mehanizam osigurava da je redoslijed ponavljanja elemenata redoslijed kojim su elementima zadnji put pristupili, od najmanje nedavno pristupljenog do nedavno pristupljenog.

Izgradnja predmemorije s najmanje korištenim (LRU) prilično je jednostavna i praktična s ovom vrstom mape. Uspješan staviti ili dobiti operacija rezultira pristupom za unos:

@Test javna praznina givenLinkedHashMap_whenAccessOrderWorks_thenCorrect () {LinkedHashMap map = new LinkedHashMap (16, .75f, true); map.put (1, null); map.put (2, null); map.put (3, null); map.put (4, null); map.put (5, null); Postavi tipke = map.keySet (); assertEquals ("[1, 2, 3, 4, 5]", keys.toString ()); map.get (4); assertEquals ("[1, 2, 3, 5, 4]", keys.toString ()); map.get (1); assertEquals ("[2, 3, 5, 4, 1]", keys.toString ()); map.get (3); assertEquals ("[2, 5, 4, 1, 3]", keys.toString ()); }

Primijetite kako redoslijed elemenata u skupu ključeva transformira se dok izvodimo operacije pristupa na karti.

Jednostavno rečeno, svaka operacija pristupa na karti rezultira redoslijedom tako da se elementu kojem se pristupi pojavljuje zadnji ako bi se iteracija trebala izvršiti odmah.

Nakon gornjih primjera, trebalo bi biti očito da a staviSve operacija generira jedan pristup unosu za svako preslikavanje na navedenoj karti.

Prirodno, ponavljanje prikaza karte ne utječe na redoslijed ponavljanja prateće karte; samo će izričiti pristup operacijama na karti utjecati na redoslijed.

LinkedHashMap također pruža mehanizam za održavanje fiksnog broja preslikavanja i za stalno ispuštanje najstarijih unosa u slučaju da treba dodati novi.

The removeEldestEntry metoda može biti nadjačana kako bi se primijenilo ovo pravilo za automatsko uklanjanje ustajalih preslikavanja.

Da bismo to vidjeli u praksi, stvorimo vlastitu povezanu klasu hash mapa, s jedinom svrhom da prisilimo na uklanjanje ustajalih preslikavanja proširivanjem LinkedHashMap:

javna klasa MyLinkedHashMap proširuje LinkedHashMap {private static final int MAX_ENTRIES = 5; public MyLinkedHashMap (int InitiCapacity, float loadFactor, boolean accessOrder) {super (InitiCapacity, loadFactor, accessOrder); } @Override zaštićeno logičko uklanjanjeEldestEntry (Map.Entry najstariji) {return size ()> MAX_ENTRIES; }}

Naše poništavanje iznad omogućit će da karta naraste do maksimalne veličine 5 unosa. Kada veličina prijeđe to, svaki novi unos umetnut će se po cijenu gubitka najstarijeg unosa na karti, tj. Unosa čije vrijeme zadnjeg pristupa prethodi svim ostalim unosima:

@Test javna praznina givenLinkedHashMap_whenRemovesEldestEntry_thenCorrect () {LinkedHashMap map = new MyLinkedHashMap (16, .75f, true); map.put (1, null); map.put (2, null); map.put (3, null); map.put (4, null); map.put (5, null); Postavi tipke = map.keySet (); assertEquals ("[1, 2, 3, 4, 5]", keys.toString ()); map.put (6, null); assertEquals ("[2, 3, 4, 5, 6]", keys.toString ()); map.put (7, null); assertEquals ("[3, 4, 5, 6, 7]", keys.toString ()); map.put (8, null); assertEquals ("[4, 5, 6, 7, 8]", keys.toString ()); }

Primijetite kako najstariji unosi na početku skupa ključeva neprestano padaju dok na kartu dodajemo nove.

5. Razmatranja učinka

Baš kao HashMap, LinkedHashMap izvodi osnovnu Karta operacije dodavanja, uklanjanja i sadržavanja u konstantnom vremenu, sve dok je hash funkcija dobro dimenzionirana. Također prihvaća null ključ, kao i null vrijednosti.

Međutim, ovo konstantno izvođenje LinkedHashMap je vjerojatno malo lošije od konstantnog vremena HashMap zbog dodanih troškova održavanja dvostruko povezanog popisa.

Ponavljanje prikaza zbirke LinkedHashMap također treba linearno vrijeme Na) slično onome od HashMap. S druge strane,LinkedHashMapLinearne vremenske performanse tijekom iteracije su bolje od HashMap'S linearno vrijeme.

To je zato što, za LinkedHashMap, n u Na) je samo broj unosa na karti bez obzira na kapacitet. Dok, za HashMap, n je sažeti kapacitet i veličina, O (veličina + kapacitet).

Faktor opterećenja i početni kapacitet definirani su točno kao za HashMap. Primijetite, međutim, to kazna za odabir pretjerano visoke vrijednosti za početni kapacitet manja je za LinkedHashMap nego za HashMap, budući da na vrijeme ponavljanja za ovu klasu ne utječe kapacitet.

6. Istodobnost

Baš kao HashMap, LinkedHashMap implementacija nije sinkronizirana. Dakle, ako ćete mu pristupiti iz više niti i ako će ga barem jedna od ovih niti strukturno promijeniti, tada mora biti sinkronizirana izvana.

Najbolje je to učiniti pri izradi:

Mapa m = Collections.synchronizedMap (nova LinkedHashMap ());

Razlika sa HashMap leži u onome što podrazumijeva strukturnu modifikaciju. U povezanim hash kartama poredanih po pristupu, samo pozivanje dobiti API rezultira strukturnom modifikacijom. Uz to su i operacije poput staviti i ukloniti.

7. Zaključak

U ovom smo članku istražili Javu LinkedHashMap klasa kao jedna od najistaknutijih implementacija Karta sučelje u smislu korištenja. Također smo istražili njegov interni rad s obzirom na razliku od HashMap koja je njegova superklasa.

Nadamo se da ćete, nakon što ste pročitali ovaj post, moći donijeti informiranije i učinkovitije odluke koju ćete implementaciju karte koristiti u vašem slučaju upotrebe.

Potpuni izvorni kod za sve primjere korištene u ovom članku možete pronaći u projektu GitHub.