为什么我需要重写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");