hashcode, equals, ==

Java 中, 每个 Java 对象都有 hashcode, 也叫散列码. 这个hashCode 经常用于确定对象的存储地址. 一般是用来判断在集合中的位置. 用来查找的.

从内存单元中的存储地址, 几乎可以判定, 两个对象是否是一个或相等.

而这个散列码实际上就是 hashMap 的 key, 因为 hashMap 是采用 key:value的方式存储的, 比如字符串“AK” 的散列码是2090,查找时, 就会到2090的位置去查找"AK", 所以, 当我们保存一个 hashMap, 具体的查找 process 是: 例如,我们要查找 "AK" 的是否存在于集合中.

1. 通过固定的哈希函数, 计算出 "AK"的散列码是 2090.

2. 到 hashMap 的 2090 内存中去查找, 如果存在对象, 那么对象就是 "AK"

但是, 散列码的类型决定了它最多可以存储 32 位整数, 但是实际的对象个数可能超过32位整数. 这时可能两个不同的对象映射到一个散列码上.

而一旦出现这种情况, 就需要继续查找, 一般这时会使用链表, 比如加入 "AK", "WP" 都使用了散列码 2090,那么,比如我们想要查找 ”WP", 流程是

1. 通过固定的哈希函数, 计算出 "WP" 的散列码时2090. 

2. 找到2090时,发现2090存储的是一个链表, 就顺着链表指针查找"WP".

public class InputCode {

    public static void main(String[] args) {
        String a = "buzzards";
        String b = "righto";
        String c = "buzzards";
        System.out.println("a: " + a.hashCode());
        System.out.println("b: " + b.hashCode());
        if (a.equals(b)) {
            System.out.println("yes1");
        } else {
            System.out.println("No1");
        }
        if (a == b) {
            System.out.println("yes2");
        } else {
            System.out.println("No2");
        }
        if (a == c) {
            System.out.println("yes3");
        } else {
            System.out.println("No3");
        }
    }

}

输出:

a: -931102253
b: -931102253
No1  (对应 a == b)
No2  (对应 a.equals(b))
yes3  (对应 a == c, a 和 c 都指向的常量(对象)的地址.)

可以看到 hashcode 是相同的 (我特意找了两个 hashcode 一样的字符串)

String a = "buzzards";  // 栈分配 a 存储空间, 指向常量 "buzzards"
String b = "righto";   // 栈分配 b 存储控制, 指向常量 "righto" String c = "buzzards";  // 栈分配 c 存储空间, 指向常量 "buzzards"

String str1 = new String("abc");  // str1, 指向的是新开辟堆内存中的地址, 而非常量的地址了.
String str2 = new String("abc");  // str2, 指向新开辟堆内存中的地址,而非常量的地址了.
str1 == str2 这个判断, 返回的就是一个 false, 因为实际上并不是一个内存单元地址. 而是堆中两块新开辟的内存单元
str1.equals(str2) 这个判断, 返回的就是一个 true, 字符串已经重写了equals方法,不再比较地址了, 而是比较字符串的值了.

String c 时, 因为判断了常量已经存在, 所以直接将 c 的指针指向了原来的常量. 所以, a 和 c 都指向了同一个内存地址, 常量 "buzzards", 所以a == c.

equals() 与 ==

== 比较基本数据类型时,比较的是值, 但是比较两个对象时, 比较的是两个对象的地址值是否相等.

所以, equals 来说, 本身就是等价于 == 号的. 但是 equals 和 == 的区别如下:

1) equals 不能作用于普通类型.

2) 如果 equals 方法被重写了, 不使用地址作为判定对象是否相等的依据, 那么 equals 就不等价于 ==了.  例如String 字符串对象就重写了equals方法

equals() 与 hashcode()

java 中, 如果判定 equals() 是真, 那么这两个对象的 hashcode() 必须是相等的. 所以实现 equals() 方法和 hashcode()的方法必须要有所考虑.

所以, 如果要重写 equals()方法, 必须要考虑 hashcode(), 而这两个方法本身都是有 Object 类带来的.

综上, 判断对象相等, 尽量还是使用 equals() 比较好,而且自己不要随意重写 equals() 方法.

原文地址:https://www.cnblogs.com/moveofgod/p/12953049.html