equals、Objects.equals、Objects.deepEquals区别和联系

892 阅读3分钟

通识

==

对于基本数据类型来说:== 比较的是

对于引用数据类型来说:== 比较的是对象的内存地址

equals()

类没有重写equals()方法:等价于通过==去比较这两个对象、即比较他们的地址

类重写了equals()方法:通常的做法是、若两个对象的内容相等,则equals()方法返回true;否则,返回fasle

为什么类没有重写equals()方法:等价于通过==去比较这两个对象?

因为Object是所有类的父类、如果没有一个类没有重写equals()方法就会使用Object的equals()方法、原码如下、所以比较的是对象的地址

public boolean equals(Object obj) {
    return (this == obj);
}

Objects.equals原码 (java.util.Objects#equals)

public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

Objects.equals和equals没啥区别、仅仅帮我们增加对null的处理;

可以理解为:

Objects.equals = equals + 对null的处理

Objects.equals(null, null);
Objects.equals(null, "null");
Objects.equals("null", null);
Objects.equals("null", "null");

true
false
false
true

Objects.deepEquals源码 (java.util.Objects#deepEquals)

public static boolean deepEquals(Object a, Object b) 
    if (a == b)
        return true;
    else if (a == null || b == null)
        return false;
    else
        return Arrays.deepEquals0(a, b);
}


static boolean deepEquals0(Object e1, Object e2) {
    assert e1 != null;
    boolean eq;
    if (e1 instanceof Object[] && e2 instanceof Object[])
        eq = deepEquals ((Object[]) e1, (Object[]) e2);
    else if (e1 instanceof byte[] && e2 instanceof byte[])
        eq = equals((byte[]) e1, (byte[]) e2);
    else if (e1 instanceof short[] && e2 instanceof short[])
        eq = equals((short[]) e1, (short[]) e2);
    else if (e1 instanceof int[] && e2 instanceof int[])
        eq = equals((int[]) e1, (int[]) e2);
    else if (e1 instanceof long[] && e2 instanceof long[])
        eq = equals((long[]) e1, (long[]) e2);
    else if (e1 instanceof char[] && e2 instanceof char[])
        eq = equals((char[]) e1, (char[]) e2);
    else if (e1 instanceof float[] && e2 instanceof float[])
        eq = equals((float[]) e1, (float[]) e2);
    else if (e1 instanceof double[] && e2 instanceof double[])
        eq = equals((double[]) e1, (double[]) e2);
    else if (e1 instanceof boolean[] && e2 instanceof boolean[])
        eq = equals((boolean[]) e1, (boolean[]) e2);
    else
        eq = e1.equals(e2);
    return eq;
}

可以理解为:

Objects.deepEquals = equals + 对null的处理 + 对数组的处理

Objects.deepEquals = Objects.equals + 对数组的处理

Demo 练习

1、如果非数组、3者等价

String a = "abc";
String b = "abc";
System.out.println(a.equals(b));
System.out.println(Objects.equals(a, b));
System.out.println(Objects.deepEquals(a, b));

true
true
true

这里走了String覆写的equals()
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    return (anObject instanceof String aString)
            && (!COMPACT_STRINGS || this.coder == aString.coder)
            && StringLatin1.equals(value, aString.value);
}
Person per1 = new Person("name");
Person per2 = new Person("name");
System.out.println(per1.equals(per2));
System.out.println(Objects.equals(per1, per2));
System.out.println(Objects.deepEquals(per1, per2));

true
true
true

/// 因为 @Data 里包含generateEqualsAndHashCodeForType、所以覆写了equals方法、属性为String最终还是会调用String的equal方法
@Data
public class Person {
    private String personName;

    public Person(String name) {
        personName = name;
    }
}

如果是基本类型的数组

int[] arr1 = {1, 2, 3};
int[] arr2 = arr1;
int[] arr3 = {1, 2, 3};
System.out.println(arr1.equals(arr2));
System.out.println(arr1.equals(arr3));

System.out.println(Objects.equals(arr1, arr2));
System.out.println(Objects.equals(arr1, arr3));

System.out.println(Objects.deepEquals(arr1, arr2));
System.out.println(Objects.deepEquals(arr1, arr3));

true
false
true
false
true
true

1、equals在二者物理地址相同的情况下返回true、如果物理地址不同、就算内容一样也会返回false;
因为数组没有覆写Object的equals

2、deepEquals只需内容一样就会返回true

如果是对象类型的数组

String[] arr1 = {"Tom", "Mary"};
String[] arr2 =arr1;
String[] arr3 = {"Tom", "Mary"};
System.out.println(arr1.equals(arr2));
System.out.println(arr1.equals(arr3));
System.out.println(Objects.equals(arr1, arr2));
System.out.println(Objects.equals(arr1, arr3));
System.out.println(Objects.deepEquals(arr1, arr2));
System.out.println(Objects.deepEquals(arr1, arr3));

false
false
true
false
false
true

和基本类型的数组一样结论
@Data
public class Person {
    private String personName;

    public Person(String name) {
        personName = name;
    }
}
Person per1 = new Person("name1");
Person per2 = new Person("name2");
Person[] arr1 = new Person[] {per1, per2};
Person[] arr2 = new Person[] {per1, per2};
System.out.println(arr1.equals(arr2));
System.out.println(Objects.deepEquals(arr1, arr2));

Person[] arr3 = new Person[] {new Person("name1"), new Person("name2")};
Person[] arr4 = new Person[] {new Person("name1"), new Person("name2")};
System.out.println(arr3.equals(arr4));
System.out.println(Objects.deepEquals(arr3, arr4));

false
true
false
true
// 数组中的对象成员重写了equals方法、内容相同即相等
public class Person {
    private String personName;
    public Person(String name) {
        personName = name;
    }
Person per1 = new Person("name1");
Person per2 = new Person("name2");
Person[] arr1 = new Person[] {per1, per2};
Person[] arr2 = new Person[] {per1, per2};
System.out.println(arr1.equals(arr2));
System.out.println(Objects.deepEquals(arr1, arr2));

Person[] arr3 = new Person[] {new Person("name1"), new Person("name2")};
Person[] arr4 = new Person[] {new Person("name1"), new Person("name2")};
System.out.println(arr3.equals(arr4));
System.out.println(Objects.deepEquals(arr3, arr4));

false
true
false
false
// 数组中的对象成员没有重写equals方法、成员的物理地址才相同



当我们想要比较两个数组内容是否相同时,就用deepEquals;
数组中的对象成员没有重写equals方法,则不推荐使用、甚至都没有办法比较、因为只能比较地址