Java I';我搞不懂hashcode和equals是如何工作的——为什么用相同参数创建的两个对象彼此不相等?
我正在深入理解Java,并尝试比较相同的对象 我创建了两个具有相同值的字符串对象,但分配给不同的变量。结果是它们有相同的散列码 在此之后,我创建了表示person的简单类,并创建了该类的两个实例,其参数与传递给构造函数的参数相同。事实证明,它们有不同的散列码 现在我不知道它是如何工作的。你能给我解释一下吗 我的代码:Java I';我搞不懂hashcode和equals是如何工作的——为什么用相同参数创建的两个对象彼此不相等?,java,object,equals,hashcode,Java,Object,Equals,Hashcode,我正在深入理解Java,并尝试比较相同的对象 我创建了两个具有相同值的字符串对象,但分配给不同的变量。结果是它们有相同的散列码 在此之后,我创建了表示person的简单类,并创建了该类的两个实例,其参数与传递给构造函数的参数相同。事实证明,它们有不同的散列码 现在我不知道它是如何工作的。你能给我解释一下吗 我的代码: public static class Person { public String name; public String lastName;
public static class Person {
public String name;
public String lastName;
public Person(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
}
public static void main(String[] args) {
String s1 = new String("foo");
String s2 = new String("foo");
System.out.println("String1 hashcode: " + s1.hashCode());
System.out.println("String2 hashcode: " + s2.hashCode());
System.out.println("Is String1 equal to String2?: " + s1.equals(s2));
Person p1 = new Person("John", "Doe");
Person p2 = new Person("John", "Doe");
System.out.println("Person1 hashcode: " + p1.hashCode());
System.out.println("Person2 hashcode: " + p2.hashCode());
System.out.println("Is Person1 equal to Person2?: " + p1.equals(p2));
}
}
我的输出:
String1 hashcode: 101574
String2 hashcode: 101574
Is String1 equal to String2?: true
Person1 hashcode: 325040804
Person2 hashcode: 1173230247
Is Person1 equal to Person2?: false
它仅对字符串的内容计算哈希代码
返回此字符串的哈希代码。字符串
对象的哈希代码计算为
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
但是,您没有在Person
中声明hashCode
方法,因此它将继承
只要是合理可行的,类对象定义的hashCode方法确实会为不同的对象返回不同的整数
如果一个类没有重写hashCode
,那么不管对象的内容如何,我们都应该为不同的对象使用不同的hash代码
与String
类似,您可以定义自己的hashCode
方法,该方法仅基于人员的内容确定其哈希代码
您还应该重写equals(Object)
,以便Person
类定义Person
实例如何彼此相等;这两种方法的定义必须一致:
hashCode的总合同为:
- 在Java应用程序的执行过程中,每当在同一对象上多次调用hashCode方法时,只要没有修改对象上的equals比较中使用的信息,hashCode方法必须始终返回相同的整数。从应用程序的一次执行到同一应用程序的另一次执行,该整数不必保持一致
- 如果根据equals(Object)方法两个对象相等,那么对两个对象中的每一个调用hashCode方法必须产生相同的整数结果
- 根据equals(java.lang.Object)方法,如果两个对象不相等,则对这两个对象中的每一个调用hashCode方法都必须产生不同的整数结果,这不是必需的。但是,程序员应该知道,为不相等的对象生成不同的整数结果可能会提高哈希表的性能
默认情况下,hashcode从对象
类继承
它是本机方法,返回内存地址的整数表示形式。这清楚地解释了为什么两个看起来一样的不同物体是不同的
唯一一种情况是它们可以相等并且具有相同的哈希代码——它们应该引用相同的内存地址
基于内容的hashcode(如String
)可以通过重写继承自对象的hashcode()
方法来实现
必须在每个重写等于的类中重写hashCode
。如果您没有这样做,您的类将违反hashCode的通用合同,这将阻止它在集合中正常工作,例如HashMap
和HashSet
String内部类具有hashcode和equals的强大实现,因此当您创建两个具有相同内存地址的String实例并检查hashcode时,它返回相同的hash
但是您实现的类Person不会继承java.lang.Object实现的hashcode和equals来检查两个对象是否相同
通过重写java.lang.Object
hashcode和equals方法实现,更新了下面的代码以供参考。这将返回您预期的结果
public static class Person {
public String name;
public String lastName;
public Person(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
@Override
public int hashCode() {
return Objects.hash(name, lastName);
}
@Override
public boolean equals(Object obj) {
if(obj==null || !(obj instanceof Person))
return false;
Person u=(Person) obj;
return u.name.equals(name) && u.lastName.equals(lastName);
}
}
public static void main(String[] args) {
String s1 = new String("foo");
String s2 = new String("foo");
System.out.println("String1 hashcode: " + s1.hashCode());
System.out.println("String2 hashcode: " + s2.hashCode());
System.out.println("Is String1 equal to String2?: " + s1.equals(s2));
Person p1 = new Person("John", "Doe");
Person p2 = new Person("John", "Doe");
System.out.println("Person1 hashcode: " + p1.hashCode());
System.out.println("Person2 hashcode: " + p2.hashCode());
System.out.println("Is Person1 equal to Person2?: " + p1.equals(p2));
}
}
你读过的文件吗?它解释了结果添加hashcode不是一个好的实现,只需使用Objects.hash(name,lastName)
。如果字段为空,最好使用Objects.equals
。谢谢您的回答。您能给我一个覆盖hashCode和equals方法的例子,在这种情况下可能会很有用吗?