最近我读了这篇文章 开发人员工作文件。
该文档是关于有效和正确地定义hashCode()和equals(),但我无法弄清楚为什么我们需要覆盖这两个方法。
我如何决定有效地实现这些方法?
最近我读了这篇文章 开发人员工作文件。
该文档是关于有效和正确地定义hashCode()和equals(),但我无法弄清楚为什么我们需要覆盖这两个方法。
我如何决定有效地实现这些方法?
当前回答
Java中的Equals和Hashcode方法
它们是java.lang. object类的方法,object类是所有类(自定义类以及java API中定义的其他类)的超类。
实现:
public boolean equals(对象obj) hashCode()
public boolean equals(对象obj)
这个方法只是检查两个对象引用x和y是否引用同一个对象。例如,它检查x是否== y。
它是自反的:对于任何参考值x, x = (x)应该返回true。
它是对称的:对于任何参考值x和y,当且仅当y = (x)返回true时,x = (y)应该返回true。
它是可传递的:对于任何参考值x、y和z,如果x = (y)返回true, y = (z)返回true,则x = (z)应该返回true。
它是一致的:对于任何参考值x和y, x.equals(y)的多次调用一致返回true或一致返回false,前提是对象上的等号比较中使用的信息没有被修改。
对于任何非空参考值x, x.equals(null)应该返回 假的。
hashCode()
此方法返回调用此方法的对象的哈希码值。此方法以整数形式返回哈希码值,支持基于哈希的集合类,如Hashtable、HashMap、HashSet等。必须在重写equals方法的每个类中重写此方法。
hashCode的一般契约是:
在Java应用程序的执行过程中,只要在同一个对象上多次调用hashCode方法,hashCode方法必须一致地返回相同的整数,前提是该对象上的等号比较中使用的信息没有被修改。
这个整数不需要在应用程序的一次执行和同一应用程序的另一次执行之间保持一致。
如果根据equals(Object)方法,两个对象相等,那么在这两个对象上调用hashCode方法必须产生相同的整数结果。
如果根据equals(java.lang.Object)方法,两个对象是不相等的,那么对每个对象调用hashCode方法必须产生不同的整数结果,这是不要求的。然而,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
相等的对象必须产生相同的哈希代码,只要它们是 相等但不相等的对象不需要产生不同的哈希码。
资源:
JavaRanch
图片
其他回答
身份不是平等。
= operator ==测试标识符。 equals(Object obj)方法比较相等性测试(即我们需要通过重写方法来告诉相等)
为什么我需要重写Java中的equals和hashCode方法?
首先我们要理解等号法的用法。
为了识别两个对象之间的差异,我们需要重写equals方法。
例如:
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
现在hashCode方法很容易理解了。
hashCode生成整数,以便将对象存储在HashMap、HashSet等数据结构中。
假设我们有如上所述的override equals Customer方法,
customer1.equals(customer2); // returns true by our own logic
在处理数据结构时,我们将对象存储在桶中(桶是文件夹的花哨名称)。如果我们使用内置哈希技术,对于以上两个客户,它会生成两个不同的哈希码。所以我们把相同的对象存储在两个不同的地方。为了避免这类问题,我们也应该基于以下原则重写hashCode方法。
不相等的实例可能具有相同的hashcode。 相同的实例应该返回相同的hashcode。
我正在研究解释“如果你只覆盖hashCode,那么当你调用myMap.put(first,someValue)时,它首先接受,计算它的hashCode并将其存储在给定的桶中。然后,当你调用myMap.put(first,someOtherValue)时,它应该根据Map文档将first替换为second,因为它们是相等的(根据我们的定义)。”:
我认为第二次添加myMap时应该是第二个对象比如myMap。put(second,someOtherValue)
让我用非常简单的话来解释这个概念。
首先,从更广泛的角度来看,我们有集合,而hashmap是集合中的数据结构之一。
要理解为什么我们必须重写equals和hashcode方法,如果需要的话,首先要理解什么是hashmap以及它的功能。
hashmap是一种以数组方式存储键值对数据的数据结构。假设是a[],其中'a'中的每个元素都是一个键值对。
此外,上述数组中的每个索引都可以是链表,因此在一个索引上有多个值。
为什么要使用hashmap呢?
如果我们必须在一个大数组中搜索,那么搜索每个数组,如果它们不是有效的,那么哈希技术告诉我们,让我们用一些逻辑预处理数组,并根据该逻辑对元素进行分组,即哈希
例如:我们有数组1、2、3、4、5、6、7、8、9、10、11,我们应用哈希函数mod 10,所以1、11将被分组在一起。因此,如果我们必须在前一个数组中搜索11,那么我们必须迭代整个数组,但当我们对它进行分组时,我们限制了迭代的范围,从而提高了速度。为了简单起见,用于存储所有上述信息的数据结构可以看作是一个2d数组
现在除了上面的hashmap还告诉它不会在其中添加任何duplicate。这就是为什么我们要重写等号和hashcode的主要原因
因此,当我们说要解释hashmap的内部工作时,我们需要找到hashmap有什么方法,以及它如何遵循上面我解释过的规则
所以hashmap有一个方法叫as put(K,V),根据hashmap,它应该遵循上面的规则,有效地分配数组,不添加任何重复
put所做的是首先为给定的键生成hashcode来决定值应该放在哪个索引中。如果那个下标处什么都没有,那么新值就会被加到那里,如果那里已经有了,那么新值就会被加到链表末尾那个下标处。但是请记住,不应该根据期望的hashmap行为添加重复项。假设你有两个整数对象aa=11 bb=11。
由于每个对象都派生自对象类,比较两个对象的默认实现是比较引用,而不是对象内部的值。因此,在上述情况下,尽管语义上相同,但两个对象都将无法通过相等性测试,并且有可能存在两个具有相同hashcode和相同值的对象,从而创建重复的对象。如果我们重写,就可以避免添加重复项。 您也可以参考详细工作
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;
int 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());
}
}
Java中的Equals和Hashcode方法
它们是java.lang. object类的方法,object类是所有类(自定义类以及java API中定义的其他类)的超类。
实现:
public boolean equals(对象obj) hashCode()
public boolean equals(对象obj)
这个方法只是检查两个对象引用x和y是否引用同一个对象。例如,它检查x是否== y。
它是自反的:对于任何参考值x, x = (x)应该返回true。
它是对称的:对于任何参考值x和y,当且仅当y = (x)返回true时,x = (y)应该返回true。
它是可传递的:对于任何参考值x、y和z,如果x = (y)返回true, y = (z)返回true,则x = (z)应该返回true。
它是一致的:对于任何参考值x和y, x.equals(y)的多次调用一致返回true或一致返回false,前提是对象上的等号比较中使用的信息没有被修改。
对于任何非空参考值x, x.equals(null)应该返回 假的。
hashCode()
此方法返回调用此方法的对象的哈希码值。此方法以整数形式返回哈希码值,支持基于哈希的集合类,如Hashtable、HashMap、HashSet等。必须在重写equals方法的每个类中重写此方法。
hashCode的一般契约是:
在Java应用程序的执行过程中,只要在同一个对象上多次调用hashCode方法,hashCode方法必须一致地返回相同的整数,前提是该对象上的等号比较中使用的信息没有被修改。
这个整数不需要在应用程序的一次执行和同一应用程序的另一次执行之间保持一致。
如果根据equals(Object)方法,两个对象相等,那么在这两个对象上调用hashCode方法必须产生相同的整数结果。
如果根据equals(java.lang.Object)方法,两个对象是不相等的,那么对每个对象调用hashCode方法必须产生不同的整数结果,这是不要求的。然而,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
相等的对象必须产生相同的哈希代码,只要它们是 相等但不相等的对象不需要产生不同的哈希码。
资源:
JavaRanch
图片
它在使用值对象时很有用。以下摘自Portland Pattern Repository:
Examples of value objects are things like numbers, dates, monies and strings. Usually, they are small objects which are used quite widely. Their identity is based on their state rather than on their object identity. This way, you can have multiple copies of the same conceptual value object. So I can have multiple copies of an object that represents the date 16 Jan 1998. Any of these copies will be equal to each other. For a small object such as this, it is often easier to create new ones and move them around rather than rely on a single object to represent the date. A value object should always override .equals() in Java (or = in Smalltalk). (Remember to override .hashCode() as well.)