Java I';我搞不懂hashcode和equals是如何工作的——为什么用相同参数创建的两个对象彼此不相等?

Java I';我搞不懂hashcode和equals是如何工作的——为什么用相同参数创建的两个对象彼此不相等?,java,object,equals,hashcode,Java,Object,Equals,Hashcode,我正在深入理解Java,并尝试比较相同的对象 我创建了两个具有相同值的字符串对象,但分配给不同的变量。结果是它们有相同的散列码 在此之后,我创建了表示person的简单类,并创建了该类的两个实例,其参数与传递给构造函数的参数相同。事实证明,它们有不同的散列码 现在我不知道它是如何工作的。你能给我解释一下吗 我的代码: public static class Person { public String name; public String lastName;

我正在深入理解Java,并尝试比较相同的对象

我创建了两个具有相同值的字符串对象,但分配给不同的变量。结果是它们有相同的散列码

在此之后,我创建了表示person的简单类,并创建了该类的两个实例,其参数与传递给构造函数的参数相同。事实证明,它们有不同的散列码

现在我不知道它是如何工作的。你能给我解释一下吗

我的代码:

 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方法的例子,在这种情况下可能会很有用吗?