Хеш принцип
Преди всичко, преди да дефинираме хеш codeа на Java, трябва да разберем Howво е хеширане и за Howво служи. Хеширането е процес на прилагане на хеш функция към някои данни. Хеш функцията е просто математическа функция. Не се тревожете за това! „Математически“ не винаги означава „сложен“. Тук това означава само, че имаме някои данни и определено правило, което картографира данните в набор от знаци (code). Например, може да е шестнадесетичен шифър. Имаме някои данни с произволен размер на входа и прилагаме хеш функция към тях. На изхода получаваме данни с фиксиран размер, да речем, 32 знака. Обикновено този вид функция преобразува голяма част от данни в малка целочислена стойност. Резултатът от работата на тази функция се нарича хеш code. Хеш функциите се използват широко в криптографията, Howто и в някои други области. Хеш функциите могат да бъдат различни,
- Конкретен обект има конкретен хешcode.
- Ако два обекта са еднакви, техните хеш codeове са еднакви. Обратното не е вярно.
- Ако хеш codeовете са различни, тогава обектите не са равни със сигурност.
- Различни обекти могат да имат един и същ хеш code. Това обаче е много малко вероятно събитие. В този момент имаме сблъсък, ситуация, при която можем да загубим данни.
„Правилната“ хеш функция минимизира вероятността от сблъсъци.
Hashcode в Java
В Java хеш функцията обикновено е свързана с
метода hashCode() . По-точно, резултатът от прилагането на хеш функция към обект е хешcode. Всеки Java обект има хеш code. Като цяло Hash Code е число, изчислено чрез метода
hashCode() на
Object
класа. Обикновено програмистите заменят този метод за своите обекти, Howто и свързания с
hashCode() метода
equals() за по-ефективна обработка на конкретни данни. Методът
hashCode() връща int (4 byteа) стойност, която е цифрово представяне на обекта. Този хешcode се използва например от колекции за по-ефективно съхранение на данни и съответно по-бърз достъп до тях. По подразбиране
hashCode()функцията за обект връща номера на клетката от паметта, където се съхранява обектът. Следователно, ако не се правят промени в codeа на приложението, тогава функцията трябва да върне същата стойност. Ако codeът се промени леко, стойността на хеш-codeа също се променя. За Howво се използва хешcodeът в Java? На първо място, Java hashcodes помагат на програмите да работят по-бързо. Например, ако сравним два обекта
o1
и
o2
от няHowъв тип, операцията
o1.equals(o2)
отнема около 20 пъти повече време от
o1.hashCode() == o2.hashCode()
.
Java е равно на ()
В родителския клас
Object
, заедно с метода
hashCode() , има също
equals() , функцията, която се използва за проверка на equalsството на два обекта. Изпълнението по подразбиране на тази функция просто проверява връзките на два обекта за тяхната еквивалентност.
equals() и
hashCode() имат свой договор, така че ако замените един от тях, трябва да замените другия, за да не нарушите този договор.
Внедряване на метода hashCode().
Пример
Нека създадем клас
Character с едно поле —
име . След това създаваме два обекта от класа
Character , character1 и
character2 и им задаваме едно и също име. Ако използваме по подразбиране
hashCode() и
equals() на класа
Object , определено ще получим различни, не еднакви обекти. Ето How работи hashcode в Java. Те ще имат различни хешcodeове, тъй като са в различни клетки на паметта и резултатът от операцията
equals() ще бъде false.
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));
}
}
Резултатът от стартирането на програмата:
Arnold
1595428806
Arnold
1072408673
false
Две 10-цифрени числа в конзолата са хеш codeове. Какво ще стане, ако искаме да имаме равни обекти, ако имат еднакви имена? Какво да правим? Отговорът: трябва да заменим методите
hashCode() и
equals() на класа Object за нашия клас
Character . Можем да го направим автоматично в IDEA IDE, просто натиснете
alt + insert на клавиатурата и изберете
Generate -> equals() и hashCode() .
![Какво е Java hashCode() - 2]()
В случая с нашия пример имаме следния code:
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));
}
}
Резултатът от изпълнението на този code:
Arnold
1969563338
Arnold
1969563338
true
Така че сега програмата идентифицира нашите обекти като равни и те имат еднакви хеш codeове.
Пример за хаш code на Java:
Ваш собствен hashCode() и equals()
Можете също така да създадете свои собствени реализации
на equals() и
hashCode() , но бъдете внимателни и не забравяйте да минимизирате сблъсъците с хешcode. Ето пример за нашите собствени методи
hashCode() и
equals() в класа
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));
}
}
И
основният клас, за да демонстрира своята работа:
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));
}
}
За Howво се използва хешcodeът?
На първо място хешcodeовете помагат на програмите да работят по-бързо. Например, ако сравним два обекта
o1
и
o2
от няHowъв тип, операцията
o1.equals(o2)
отнема около 20 пъти повече време от o1.hashCode() == o2.hashCode(). В Java принципът на хеширане стои зад някои популярни колекции, като
HashMap ,
HashSet и
HashTable .
Заключение
Всеки Java обект има
методите hashCode() и
equals(), наследени от класа
Object . За да получите добър работещ механизъм за equalsство, по-добре отменете методите
hashcode() и
equals() за вашите собствени класове. Използването на хешcodeове кара програмите да работят по-бързо.
GO TO FULL VERSION