Principiul Hash
În primul rând, înainte de a defini codul hash Java, trebuie să înțelegem ce este hashing și pentru ce este acesta. Hashing este un proces de aplicare a unei funcții hash unor date. O funcție hash este doar o funcție matematică. Nu vă faceți griji pentru asta! „Matematic” nu înseamnă întotdeauna „complicat”. Aici înseamnă doar că avem niște date și o anumită regulă care mapează datele într-un set de caractere (cod). De exemplu, ar putea fi un cifru hexazecimal. Avem câteva date de orice dimensiune la intrare și le aplicăm o funcție hash. La ieșire, obținem date de dimensiune fixă, să zicem, 32 de caractere. De obicei, acest tip de funcție convertește o bucată mare de date într-o valoare întreagă mică. Rezultatul acestei funcții se numește cod hash. Funcțiile hash sunt utilizate pe scară largă în criptografie și în alte domenii. Funcțiile hash pot fi diferite,
- Un anumit obiect are un anumit hashcode.
- Dacă două obiecte sunt egale, codurile lor hash sunt aceleași. Reversul nu este adevărat.
- Dacă codurile hash sunt diferite, atunci obiectele nu sunt egale cu siguranță.
- Diferite obiecte pot avea același cod hash. Cu toate acestea, este un eveniment foarte puțin probabil. În acest moment, avem o coliziune, o situație în care putem pierde date.
Funcția hash „corectă” minimizează probabilitatea de coliziuni.
Hashcode în Java
În Java, funcția hash este de obicei conectată la
metoda hashCode() . Mai exact, rezultatul aplicării unei funcții hash unui Obiect este un hashcode. Fiecare obiect Java are un cod hash. În general, Hash Code este un număr calculat prin metoda
hashCode() a
Object
clasei. De obicei, programatorii înlocuiesc această metodă pentru obiectele lor, precum și în legătură cu metoda
hashCode() equals
() pentru o procesare mai eficientă a anumitor date. Metoda
hashCode() returnează o valoare int (4 octeți), care este o reprezentare numerică a obiectului. Acest cod hash este folosit, de exemplu, de colecții pentru o stocare mai eficientă a datelor și, în consecință, un acces mai rapid la acestea. În mod implicit,
hashCode()funcția pentru un obiect returnează numărul celulei de memorie în care este stocat obiectul. Prin urmare, dacă nu se fac modificări la codul aplicației, atunci funcția ar trebui să returneze aceeași valoare. Dacă codul se modifică ușor, se schimbă și valoarea hashcode. Pentru ce este folosit codul hash în Java? În primul rând, codurile hash Java ajută programele să ruleze mai repede. De exemplu, dacă comparăm două obiecte
o1
și
o2
de un anumit tip, operația
o1.equals(o2)
durează de aproximativ 20 de ori mai mult decât
o1.hashCode() == o2.hashCode()
.
Java este egal()
În clasa părinte
Object
, alături de metoda
hashCode() există și
equals() , funcția care este folosită pentru a verifica egalitatea a două obiecte. Implementarea implicită a acestei funcții verifică pur și simplu legăturile a două obiecte pentru echivalența lor.
equals() și
hashCode() au contractul lor, așa că dacă îl suprascrieți pe unul dintre ele, ar trebui să îl înlocuiți pe celălalt, pentru a nu rupe acest contract.
Implementarea metodei hashCode().
Exemplu
Să creăm o clasă
Caracter cu un câmp —
nume . După aceea, creăm două obiecte din clasa
Character , caracterul1 și
caracterul2 și le setăm același nume. Dacă folosim
hashCode() și
equals() implicit ale clasei
Object , cu siguranță vom obține obiecte diferite, nu egale. Așa funcționează hashcode în Java. Vor avea coduri hash diferite, deoarece sunt în celule de memorie diferite, iar rezultatul operației
equals() va fi fals.
import java.util.Objects;
public class Character {
private String Name;
public Character(String name) {
Name = name;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public static void main(String[] args) {
Character character1 = new Character("Arnold");
System.out.println(character1.getName());
System.out.println(character1.hashCode());
Character character2 = new Character("Arnold");
System.out.println(character2.getName());
System.out.println(character2.hashCode());
System.out.println(character2.equals(character1));
}
}
Rezultatul rulării programului:
Arnold
1595428806
Arnold
1072408673
false
Două numere de 10 cifre din consolă sunt coduri hash. Ce se întâmplă dacă vrem să avem obiecte egale dacă au aceleași nume? Ce ar trebui sa facem? Răspunsul: ar trebui să suprascriem metodele
hashCode() și
equals() ale clasei Object pentru clasa noastră
Character . Am putea să o facem automat în IDEA IDE, doar apăsați
alt + inserare pe tastatură și alegeți
Generare -> equals() și hashCode() .
![Ce este Java hashCode() - 2]()
În cazul exemplului nostru, avem următorul cod:
import java.util.Objects;
public class Character {
private String Name;
public Character(String name) {
Name = name;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Character)) return false;
Character character = (Character) o;
return getName() != null ? getName().equals(character.getName()) : character.getName() == null;
}
@Override
public int hashCode() {
return getName() != null ? getName().hashCode() : 0;
}
public static void main(String[] args) {
Character character1 = new Character("Arnold");
System.out.println(character1.getName());
System.out.println(character1.hashCode());
Character character2 = new Character("Arnold");
System.out.println(character2.getName());
System.out.println(character2.hashCode());
System.out.println(character2.equals(character1));
}
}
Rezultatul rulării acestui cod:
Arnold
1969563338
Arnold
1969563338
true
Deci acum programul identifică obiectele noastre ca fiind egale și au aceleași coduri hash.
Exemplu de hashcode Java:
Propriul tău hashCode() și equals()
De asemenea, puteți crea propriile realizări
equals() și
hashCode() , dar aveți grijă și amintiți-vă să minimizați coliziunile hashcode. Iată un exemplu de propriile noastre metode
hashCode() și
equals() în clasa
Student :
import java.util.Date;
public class Student {
String surname;
String name;
String secondName;
Long birthday; // Long instead of long is used by Gson/Jackson json parsers and various orm databases
public Student(String surname, String name, String secondName, Date birthday ){
this.surname = surname;
this.name = name;
this.secondName = secondName;
this.birthday = birthday == null ? 0 : birthday.getTime();
}
//Java hashcode example
@Override
public int hashCode(){
//TODO: check for nulls
//return surname.hashCode() ^ name.hashCode() ^ secondName.hashCode() ^ (birthday.hashCode());
return (surname + name + secondName + birthday).hashCode();
}
@Override
public boolean equals(Object other_) {
Student other = (Student)other_;
return (surname == null || surname.equals(other.surname) )
&& (name == null || name.equals(other.name))
&& (secondName == null || secondName.equals(other.secondName))
&& (birthday == null || birthday.equals(other.birthday));
}
}
Și clasa
principală pentru a-și demonstra munca:
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
public class Main {
static HashMap<Student, Integer> cache = new HashMap<Student, Integer>(); // <person, targetPriority>
public static void main(String[] args) {
Student sarah1 = new Student("Sarah","Connor", "Jane", null);
Student sarah2 = new Student("Sarah","Connor", "Jane", new Date(1970, 01-1, 01));
Student sarah3 = new Student("Sarah","Connor", "Jane", new Date(1959, 02-1, 28)); // date not exists
Student john = new Student("John","Connor", "Kyle", new Date(1985, 02-1, 28)); // date not exists
Student johnny = new Student("John","Connor", "Kyle", new Date(1985, 02-1, 28)); // date not exists
System.out.println(john.hashCode());
System.out.println(johnny.hashCode());
System.out.println(sarah1.hashCode());
System.out.println();
cache.put(sarah1, 1);
cache.put(sarah2, 2);
cache.put(sarah3, 3);
System.out.println(new Date(sarah1.birthday));
System.out.println();
cache.put(john, 5);
System.out.println(cache.get(john));
System.out.println(cache.get(johnny));
cache.put(johnny, 7);
System.out.println(cache.get(john));
System.out.println(cache.get(johnny));
}
}
Pentru ce este folosit codul hash?
În primul rând, codurile hash ajută programele să ruleze mai repede. De exemplu, dacă comparăm două obiecte
o1
și
o2
de un anumit tip, operația
o1.equals(o2)
durează de aproximativ 20 de ori mai mult decât o1.hashCode() == o2.hashCode(). În Java, principiul hashing stă în spatele unor colecții populare, cum ar fi
HashMap ,
HashSet și
HashTable .
Concluzie
Fiecare obiect Java are
metodele hashCode() și
equals() moștenite de la clasa
Object . Pentru a obține un mecanism de egalitate bun, ar fi mai bine să suprascrieți metodele
hashcode() și
equals() pentru propriile clase. Utilizarea codurilor hash face ca programele să ruleze mai rapid.
GO TO FULL VERSION