为什么我需要重写Java中的equals和hashCode方法?
最近我通读了这篇文章 . 本文档的全部内容都是关于有效和正确地定义为什么我需要重写Java中的equals和hashCode方法?,java,equals,hashcode,Java,Equals,Hashcode,最近我通读了这篇文章 . 本文档的全部内容都是关于有效和正确地定义hashCode()和equals()的,但是我无法理解为什么我们需要覆盖这两个方法 我如何才能做出有效实施这些方法的决定?因为如果不覆盖它们,将使用对象中的默认实现 鉴于实例相等性和hascode值通常需要了解对象的组成,它们通常需要在类中重新定义以具有任何实际意义。因为如果不重写它们,则将在对象中使用默认实现 鉴于实例相等性和hascode值通常需要了解对象的组成,它们通常需要在类中重新定义,以具有任何实际意义。假设您的类(
hashCode()
和equals()
的,但是我无法理解为什么我们需要覆盖这两个方法
我如何才能做出有效实施这些方法的决定?因为如果不覆盖它们,将使用对象中的默认实现
鉴于实例相等性和hascode值通常需要了解对象的组成,它们通常需要在类中重新定义以具有任何实际意义。因为如果不重写它们,则将在对象中使用默认实现 鉴于实例相等性和hascode值通常需要了解对象的组成,它们通常需要在类中重新定义,以具有任何实际意义。假设您的类(A)聚合了另外两个(B)(C),并且您需要在哈希表中存储(A)的实例。默认实现只允许区分实例,但不允许通过(B)和(C)区分实例。所以A的两个实例可以相等,但默认值不允许您以正确的方式比较它们 假设有一个类(A)聚合了另外两个(B)(C),并且需要在哈希表中存储(A)的实例。默认实现只允许区分实例,但不允许通过(B)和(C)区分实例。所以A的两个实例可以相等,但默认值不允许您以正确的方式比较它们 它在使用时很有用。以下是该报告的摘录: 价值对象的例子是事物 比如数字、日期、货币和货币 串。通常,它们都很小 使用相当广泛的对象。 他们的身份是基于他们的国家 而不是他们的对象身份。 这样,您就可以拥有多个副本 具有相同的概念值对象 这样我就可以有多份 对象,该对象表示1月16日的日期 1998这些副本中的任何一份都是相等的。一小会儿 像这样的对象,它通常是 更容易创建新的和移动 他们在附近,而不是依靠一个 表示日期的单个对象 值对象应始终重写 .equals()在Java中(或=在Smalltalk中)。 (请记住将.hashCode()重写为 嗯。) 它在使用时很有用。以下是该报告的摘录: 价值对象的例子是事物 比如数字、日期、货币和货币 串。通常,它们都很小 使用相当广泛的对象。 他们的身份是基于他们的国家 而不是他们的对象身份。 这样,您就可以拥有多个副本 具有相同的概念值对象 这样我就可以有多份 对象,该对象表示1月16日的日期 1998这些副本中的任何一份都是相等的。一小会儿 像这样的对象,它通常是 更容易创建新的和移动 他们在附近,而不是依靠一个 表示日期的单个对象 值对象应始终重写 .equals()在Java中(或=在Smalltalk中)。 (请记住将.hashCode()重写为 嗯。) 必须在每个 重写等于()的类。失败 这样做将导致违反 工程总承包 Object.hashCode(),这将阻止 你的班级不能正常运作 与所有基于哈希的 集合,包括HashMap, HashSet和Hashtable
摘自约书亚·布洛赫的《有效的Java》 通过一致地定义
equals()
和hashCode()
,可以提高类作为基于哈希的集合中的键的可用性。正如hashCode的API文档所解释的:“支持此方法是为了方便使用Hashtable,例如java.util.Hashtable
提供的Hashtable。”
关于如何有效实施这些方法的问题,最好的答案是建议您阅读的第3章
必须在每个
重写等于()的类。失败
这样做将导致违反
工程总承包
Object.hashCode(),这将阻止
你的班级不能正常运作
与所有基于哈希的
集合,包括HashMap,
HashSet和Hashtable
摘自约书亚·布洛赫的《有效的Java》 通过一致地定义
equals()
和hashCode()
,可以提高类作为基于哈希的集合中的键的可用性。正如hashCode的API文档所解释的:“支持此方法是为了方便使用Hashtable,例如java.util.Hashtable
提供的Hashtable。”
关于如何有效地实现这些方法的问题,最好的答案是建议您阅读的第3章。这两种方法都是在对象类中定义的。两者都是最简单的实现。因此,当您需要向这些方法添加更多的实现时,您可以在类中进行重写
对于Ex:equals(),对象中的方法仅检查其在引用上的相等性。所以,如果您还需要比较它的状态,那么您可以像在String类中那样重写它。这两个方法都是在Object类中定义的。两者都是最简单的实现。因此,当您需要向这些方法添加更多的实现时,您可以在类中进行重写
对于Ex:equals(),对象中的方法仅检查其在引用上的相等性。所以,如果您还需要比较它的状态,那么您可以像在String类中那样重写它。简单地说,对象中的equals方法检查引用相等,其中,当属性相等时,类的两个实例在语义上仍然相等。例如,当将对象放入使用equals和hashcode的容器中时,这一点很重要,如和。假设我们有一个类,如:
public class Foo {
String id;
String whatevs;
Foo(String id, String whatevs) {
this.id = id;
this.whatevs = whatevs;
}
}
<
Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");
public class Foo {
String id;
String whatevs;
Foo(String id, String whatevs) {
this.id = id;
this.whatevs = whatevs;
}
@Override
public boolean equals(Object other) {
if (other instanceof Foo) {
return ((Foo)other).id.equals(this.id);
}
}
@Override
public int hashCode() {
return this.id.hashCode();
}
}
public class MyClass {
private final String importantField;
private final String anotherField;
public MyClass(final String equalField, final String anotherField) {
this.importantField = equalField;
this.anotherField = anotherField;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((importantField == null) ? 0 : importantField.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final MyClass other = (MyClass) obj;
if (importantField == null) {
if (other.importantField != null)
return false;
} else if (!importantField.equals(other.importantField))
return false;
return true;
}
}
MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");
public class Employee {
String name;
int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Employee))
return false;
Employee employee = (Employee) obj;
return employee.getAge() == this.getAge()
&& employee.getName() == this.getName();
}
// commented
/* @Override
public int hashCode() {
int result=17;
result=31*result+age;
result=31*result+(name!=null ? name.hashCode():0);
return result;
}
*/
}
public class ClientTest {
public static void main(String[] args) {
Employee employee = new Employee("rajeev", 24);
Employee employee1 = new Employee("rajeev", 25);
Employee employee2 = new Employee("rajeev", 24);
HashSet<Employee> employees = new HashSet<Employee>();
employees.add(employee);
System.out.println(employees.contains(employee2));
System.out.println("employee.hashCode(): " + employee.hashCode()
+ " employee2.hashCode():" + employee2.hashCode());
}
}
false
employee.hashCode(): 321755204 employee2.hashCode():375890482
true
employee.hashCode(): -938387308 employee2.hashCode():-938387308
public boolean equals(Object obj) {
return (this == obj);
}
myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?
Your hashCode() implementation : intObject%9.
Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...
import java.util.HashMap;
public class Employee {
String name;
String mobile;
public Employee(String name,String mobile) {
this.name=name;
this.mobile=mobile;
}
@Override
public int hashCode() {
System.out.println("calling hascode method of Employee");
String str=this.name;
Integer sum=0;
for(int i=0;i<str.length();i++){
sum=sum+str.charAt(i);
}
return sum;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
System.out.println("calling equals method of Employee");
Employee emp=(Employee)obj;
if(this.mobile.equalsIgnoreCase(emp.mobile)){
System.out.println("returning true");
return true;
}else{
System.out.println("returning false");
return false;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Employee emp=new Employee("abc", "hhh");
Employee emp2=new Employee("abc", "hhh");
HashMap<Employee, Employee> h=new HashMap<>();
//for (int i=0;i<5;i++){
h.put(emp, emp);
h.put(emp2, emp2);
//}
System.out.println("----------------");
System.out.println("size of hashmap: "+h.size());
}
}
class A {
int i;
// Hashing Algorithm
if even number return 0 else return 1
// Equals Algorithm,
if i = this.i return true else false
}
Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...
Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..
Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...
Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.
------------------------------
Now I have overriden Customer class equals method as follows:
@Override
public boolean equals(Object obj) {
if (this == obj) // it checks references
return true;
if (obj == null) // checks null
return false;
if (getClass() != obj.getClass()) // both object are instances of same class or not
return false;
Customer other = (Customer) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference
return false;
return true;
}
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2); // returns true by our own logic
customer1.equals(customer2); // returns true by our own logic
public class Person {
String name;
int age;
String socialSecurityNumber;
public Person(String name, int age, String socialSecurityNumber) {
this.name = name;
this.age = age;
this.socialSecurityNumber = socialSecurityNumber;
}
@Override
public boolean equals(Object p) {
//Person is same if social security number is same
if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
return true;
} else {
return false;
}
}
@Override
public int hashCode() { //I am using a hashing function in String.java instead of writing my own.
return socialSecurityNumber.hashCode();
}
}
public class Order {
String[] items;
public void insertOrder(String[] items)
{
this.items=items;
}
}
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
Person p1=new Person("Tom",32,"548-56-4412");
Person p2=new Person("Jerry",60,"456-74-4125");
Person p3=new Person("Sherry",38,"418-55-1235");
Order order1=new Order();
order1.insertOrder(new String[]{"mouse","car charger"});
Order order2=new Order();
order2.insertOrder(new String[]{"Multi vitamin"});
Order order3=new Order();
order3.insertOrder(new String[]{"handbag", "iPod"});
Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
hashtable.put(p1,order1);
hashtable.put(p2,order2);
hashtable.put(p3,order3);
//The line below will fail if Person class does not override hashCode()
Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
for(String item:tomOrder.items)
{
System.out.println(item);
}
}
}
public class Car {
private String color;
public Car(String color) {
this.color = color;
}
public boolean equals(Object obj) {
if(obj==null) return false;
if (!(obj instanceof Car))
return false;
if (obj == this)
return true;
return this.color.equals(((Car) obj).color);
}
public static void main(String[] args) {
Car a1 = new Car("green");
Car a2 = new Car("red");
//hashMap stores Car type and its quantity
HashMap<Car, Integer> m = new HashMap<Car, Integer>();
m.put(a1, 10);
m.put(a2, 20);
System.out.println(m.get(new Car("green")));
}
}
public int hashCode(){
return this.color.hashCode();
}
put(k, v){
hash(k);
index=hash & (n-1);
}
Person p1 = new Person("A",23);
Person p2 = new Person("A",23);
HashMap map = new HashMap();
map.put(p1,"value 1");
map.put(p2,"value 2");
public class Employee {
private int empId;
private String empName;
public Employee(int empId, String empName) {
super();
this.empId = empId;
this.empName = empName;
}
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + "]";
}
@Override
public int hashCode() {
return empId + empName.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(this instanceof Employee)) {
return false;
}
Employee emp = (Employee) obj;
return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
}
}
public class Test {
public static void main(String[] args) {
Employee emp1 = new Employee(101,"Manash");
Employee emp2 = new Employee(101,"Manash");
Employee emp3 = new Employee(103,"Ranjan");
System.out.println(emp1.hashCode());
System.out.println(emp2.hashCode());
System.out.println(emp1.equals(emp2));
System.out.println(emp1.equals(emp3));
}
}
public class Rishav {
private String rshv;
public Rishav(String rshv) {
this.rshv = rshv;
}
/**
* @return the rshv
*/
public String getRshv() {
return rshv;
}
/**
* @param rshv the rshv to set
*/
public void setRshv(String rshv) {
this.rshv = rshv;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Rishav) {
obj = (Rishav) obj;
if (this.rshv.equals(((Rishav) obj).getRshv())) {
return true;
} else {
return false;
}
} else {
return false;
}
}
@Override
public int hashCode() {
return rshv.hashCode();
}
}
import java.util.HashSet;
import java.util.Set;
public class TestRishav {
public static void main(String[] args) {
Rishav rA = new Rishav("rishav");
Rishav rB = new Rishav("rishav");
System.out.println(rA.equals(rB));
System.out.println("-----------------------------------");
Set<Rishav> hashed = new HashSet<>();
hashed.add(rA);
System.out.println(hashed.contains(rB));
System.out.println("-----------------------------------");
hashed.add(rB);
System.out.println(hashed.size());
}
}
true
-----------------------------------
true
-----------------------------------
1
true
-----------------------------------
false
-----------------------------------
2
public class Person {
private Integer age;
private String name;
..getters, setters, constructors
}
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1 == person2 ); --> will print false!
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
name.equals(person.name);
}
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1 == person2 ); --> will print false!
System.out.println ( person1.equals(person2) ); --> will print true!
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1.equals(person2) ); --> will print true!
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
public class Person {
private Integer age;
private String name;
..getters, setters, constructors
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");