【问题标题】:Role of == operator in Java checking memory address==运算符在Java检查内存地址中的作用
【发布时间】:2019-06-27 02:25:41
【问题描述】:

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

学生实体: 公共类 Student 实现 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 中输入 Duplicates 以检查覆盖 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 不同的对象/输入总是 可能(根据“hash”的定义代码”)..相反(相同的输入 -> 相同的哈希码)应该始终保持(在“良好的哈希码”中)..您的哈希码在这些术语中是“坏的”。
  • “内存位置”不应该是影响大多数 Java 编程的概念。您肯定需要的最接近的概念是“这两个引用是对同一对象还是对不同对象?”。当然,正如已经明确指出的那样,相等的 hashCodes 肯定并不意味着它们是同一个对象。

标签: java hashmap equals hashcode


【解决方案1】:

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

您的评估显示以下输出:

stringops.Student@955a0720

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

Have a look at how Java implementstoString:

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

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

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

【讨论】:

  • 所以判断两个对象是否在同一个内存位置的终极测试是通过检查 (obj1 == obj2) ???
  • 是的,因为这个操作符是专门为这个用例制作的
  • 一个内存地址一次只能有一个对象。因此,只有当它是相同的对象而不是相似的对象(可以通过 equals 方法检测到)时,只有 == 才会返回 true
  • 谢谢你们的帮助!!
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

    如果他/她希望覆盖某个特定类的开发人员,则由他/她决定。类的开发人员可能会选择(尽管是一种不好的做法)为类的所有对象重新运行相同的常量 int 值。

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

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

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

    还有一个相关的概念:equals 和 hascode 方法的契约。它表示如果两个对象通过调用 equals 返回 true,则两个对象必须具有相同的哈希码。请注意,这是定义的合同,但由开发人员开发类并编写哈希码方法以遵守合同。一个糟糕的实现可能会导致两个对象返回不同的hascode,对于equals方法返回true。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2013-03-29
      • 2021-09-01
      • 2017-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多