【Java学习笔记】equal与==

513 阅读4分钟

==

对于基本数据类型来说,主要是匹配值是否相同。

public class Equals {
    public static void main(String[] args) {
        int a = 1;
        int b = 1;
        System.out.println(a == b);
        System.out.println(b == a);
    }
}

输出结果如下:

true
true

对于引用类型来说,==匹配的是两个是否指向了同一内存区域。

public class Equals {
​
    static Person person1 = new Person();
​
    static Person person2 = new Person();
​
    public static void main(String[] args) {
        System.out.println(person1 == person2);
    }
}

上述通过new关键字分别创建了2个对象,此时我们用==进行比较,结果如下

false

这里涉及到对象创建的只是了,后续在虚拟机相关笔记中体现。

equal

equals 是 Java 中所有对象的父类,即 Object 类定义的一个方法。它只能比较对象,它表示的是引用双方的值是否相等

public class Equals {
    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person();
        person1.setName("1");
        person2.setName("1");
        System.out.println(person1.getName().equals(person2.getName()));
    }
}

equals 用作对象之间的比较具有如下特性

  • 自反性:对于任何非空引用 x 来说,x.equals(x) 应该返回 true。
  • 对称性:对于任何非空引用 x 和 y 来说,若x.equals(y)为 true,则y.equals(x)也为 true。
  • 传递性:对于任何非空引用的值来说,有三个值,x、y 和 z,如果x.equals(y) 返回true,y.equals(z) 返回true,那么x.equals(z) 也应该返回true。
  • 一致性:对于任何非空引用 x 和 y 来说,如果 x.equals(y) 相等的话,那么它们必须始终相等。
  • 非空性:对于任何非空引用的值 x 来说,x.equals(null) 必须返回 false。

String的equal实现

String也是在日常编程中经常使用的修饰符之一,它和其它基本数据类型不同,String本身是一个常量(final),其不能被其他对象所继承(至于原因,据说是开发者觉得String实现已经非常完美了,不想开发者任意扩展来破坏它),其一经赋值便无法再改变,继承自Object,所以Object具有的能力在String中都可以找到相对于的。

此处我们重点分析,String中的equal实现。

public boolean equals(Object anObject) {
    // 首先满足自反性,自己传入自己确保返回为true
    if (this == anObject) {
        return true;
    }
    // 确保传入的Object为String类型
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // 判断长度是否相等,如果不等一定为false
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // 开始逐个字符比较,如果发现不相等的字符,则返回false
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

String中equals的实现总结来说可以是以下几点:

1.判断是否传入的是自身,如果是返回true。

2.判断是否是String对象,如果不是返回true。

2.1 如果是String对象 则比较传入的len是否一致,如果一致,则继续比较。

2.2 比较字符,如果字符不一致,则返回false,反之继续比较直到比较完全(这里是一个循环全量匹配)

这里再提示一下,你可能有疑惑什么时候是

if (this == anObject) {
  return true;
}

这个判断语句如何才能返回 true?因为都是字符串啊,字符串比较的不都是堆空间吗,猛然一看发现好像永远也不会走,但是你忘记了 String.intern() 方法,它表示的概念在不同的 JDK 版本有不同的区分

在 JDK1.7 及以后调用 intern 方法是判断运行时常量池中是否有指定的字符串,如果没有的话,就把字符串的引用添加到常量池中,并不是复制一份对象放入其中了。

重写HashCode

equals 方法和 hashCode 都是 Object 中定义的方法,它们经常被一起重写。

equals 方法是用来比较对象大小是否相等的方法,hashcode 方法是用来判断每个对象 hash 值的一种方法。如果只重写 equals 方法而不重写 hashcode 方法,很可能会造成两个不同的对象,它们的 hashcode 也相等,造成冲突。比如

String str1 = "通话";
String str2 = "重地";
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());

上述两个字符串所代表的hashcode就是相同的。

1179395
1179395

它们两个的 hashcode 相等,但是 equals 可不相等。

关于equals总结如下

  • 如果在 Java 运行期间对同一个对象调用 hashCode 方法后,无论调用多少次,都应该返回相同的 hashCode,但是在不同的 Java 程序中,执行 hashCode 方法返回的值可能不一致。
  • 如果两个对象的 equals 相等,那么 hashCode 必须相同
  • 如果两个对象 equals 不相等,那么 hashCode 也有可能相同,所以需要重写 hashCode 方法,因为你不知道 hashCode 的底层构造(后续可以解析jvm源码深入认识hashcode的构造),所以你需要重写 hashCode 方法,来为不同的对象生成不同的 hashCode 值,这样能够提高不同对象的访问速度。
  • hashCode 通常是将地址转换为整数来实现的。

参考文献:github.com/crisxuan/be…