==运算符在Java检查内存地址中的作用

Role of == operator in Java checking memory address

直到今天,我一直相信具有相同哈希码的两个对象意味着它们都具有相同的内存位置。但是下面的一段代码讲述了一个完全不同的故事:

学生实体: public class 学生实现 Comparable {

int id;
int marks;
String Subject;

public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public int getMarks() {
    return marks;
}
public void setMarks(int marks) {
    this.marks = marks;
}
public String getSubjects() {
    return Subject;
}
public void setSubject(String subject) {
    Subject = subject;
}

public Student() {

}
public Student(int id, String subject, int marks) {
    super();
    this.id = id;
    this.marks = marks;
    Subject = subject;
}
@Override
public int compareTo(Student o) {
    if (this.getId()>(o.getId()))
    return 1;

    if (this.getId()<(o.getId()))
    return -1;

    return 1;
}

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((Subject == null) ? 0 : Subject.hashCode());
        result = prime * result + id;
        result = prime * result + marks;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (Subject == null) {
            if (other.Subject != null)
                return false;
        } else if (!Subject.equals(other.Subject))
            return false;
        if (id != other.id)
            return false;
        if (marks != other.marks)
            return false;
        return true;
    }


}

在 Hashmap 中输入重复项以检查覆盖 equals 和 hashcode() 是否有效:

public class TestHashSet3 {

    static Student s1;
    static Student s2;
    static Student s3;

    public static void main(String[] args) {
        setStudent();
        testSet();
        testMap();
 }

    static void testMap() {
        Map<Student, String> empMap = new HashMap<>();
        empMap.put(s1, "Arun");
        empMap.put(s2, "Shivam");
        empMap.put(s3, "Varun");
        System.out.println("HashMap executed = ");
        for (Map.Entry<Student, String> obj : empMap.entrySet()) {
            System.out.println(obj  +  " ");
        }
    }

    static void testSet() {
        Set<Student> set = new HashSet<>();
        set.add(s1);
        set.add(s2);
        set.add(s3);
        System.out.println("HashSet executed = ");
        for (Student student : set) {
            System.out.println(student  +  " ");
        }

    }

    static void setStudent() {
        s1 = new Student(124, "Maths", 50);
        s2 = new Student(124, "Maths", 50);
        s3 = new Student(124, "Maths", 50);
    }
}

在最后一张截图中,我们可以看到这个==obj 原来是错误的。但是为什么?

嗯,hashCode() 总是 return 内存地址并不完全正确。在您的特定情况下,您将函数覆盖为基本上 return Subject 引用的 hashCode。

您的评估显示以下输出:

stringops.Student@955a0720

这可能有点令人困惑,因为这实际上 不是 裸内存地址,而是对对象的 toString() 方法的调用。

Have a look at how Java implements toString:

getClass().getName() + '@' + Integer.toHexString(hashCode())

所以,事实上,这两个对象具有不同的内存位置,但是因为您覆盖了 hashCode(),所以您将看不到它们。此外,无法覆盖 Java 如何选择一个对象的内存地址(除了一些 hack 可能),但是,两个对象不能有相同的地址。

下次请包含更多文本而不是屏幕截图,以提高您的问题对其他人的搜索能力。

hashcode 是一个 int 值,由 hascode() 方法 returned。

Object.java 定义了 hascode() 并且每个 java class 都是 Object.java 的子 class,因此每个 class 都继承了它.

如果 he/she 希望覆盖它,则由特定 class 的开发人员决定。 class 的开发人员可能会选择(尽管是一种不好的做法)为 class.

的所有对象重新运行相同的常量 int 值

通常 hascode 取决于对象的一个​​或多个属性的值。尽管开发人员可能会尽力 return 唯一的哈希码,但仍然(哈希码冲突)两个不同的对象最终可能会得到相同的哈希码。

At 一次只能将一个内存位置分配给一个对象。

两个不同对象的哈希码(驻留在内存中的两个不同地址)可能相同也可能不同

还有一个相关概念:平等契约和 hascode 方法。它表示如果两个对象通过调用 equals 得到了 true returned,那么两个对象必须具有相同的哈希码。请注意,这是一个定义的契约,但这取决于开发人员开发 class 并编写 hashcode 方法以遵守契约。一个糟糕的实现可能会导致不同的 hascodes 被两个对象 returned return 对 equals 方法为真。

您刚刚正确地识别出两个不同的对象——即不在同一内存地址的两个对象——确实可以具有相同的散列码。规则是如果两个对象通过 .equals() 方法相等,那么它们应该产生相同的散列码。除了这个和“不同的对象应该尝试具有不同的哈希码”的一般想法之外,没有要求不同位置的对象应该有不同的哈希值。

不过,这是一件好事。例如,两个具有相同字符序列的不同 String 对象应该直观地具有相同的哈希码,以便 HashMap<String, T> 可以正确地查找字符串。这样,提供一个与用作键的对象不同的 String 对象,但具有相同的逻辑值,将正常工作;具有相同字符序列的所有 String 散列到同一位置。