Java中==和equals的使用区别

2019-05-10  本文已影响0人  文景大大

在Java中“==”的含义需要看比较的是什么类型的数据。

如果比较的都是基本类型的数据,那么“==”的含义就是比较它们之间的值是否相等:

public static void main(String[] args) throws Exception {

        int a = 10;
        int b = 10;
        double c = 10.0;
        double d = 10.0;

        // print true
        System.out.println(a == b);
        // print true
        System.out.println(a == c);
        // print true
        System.out.println(c == d);

    }

如果比较的都是引用数据类型,那么比较的是两者之间存放内容的地址是否是相等,而不是比较它们的内容,如何证明这一点呢?我们来看如下的例子:

    public static void main(String[] args) throws Exception {

        String s1 = "zhangsan";
        String s2 = "zhangsan";
        String s3 = new String("zhangsan");
        String s4 = new String("zhangsan");
        String s5 = s3;

        // print true
        System.out.println(s1 == s2);
        // print false
        System.out.println(s1 == s3);
        // print false
        System.out.println(s3 == s4);
        // print true
        System.out.println(s3 == s5);

    }

s1和s2都是字符串常量值,它们被放置在栈内存中,相同内容只会保留一份,所以当比较它们的时候,都是指的同一份内容,即地址也是相同的,因此返回true;

s3是新建了一个对象,存放在堆内存中,它和s1虽然内容相等,但是存放的地方不一样,地址当然也是不同的,因此它们比较的结果是返回false;

s4是仿照s3重新建立了一个对象,在堆内存中,即使相同内容的对象也是两个不同的对象,所以它们地址是不同的,比较的结果是false;

s5是赋值了s3对象所在的地址,那么此时s3和s5都是指向堆内存中相同的地址,因此它们比较的结果是返回true;

知道了“==”的作用后,我们再来看看equals的作用。equals最早是在Object类中出现的,因此,可以理解为所有的类都是具有equals方法的,如下是Object中的相关源码:

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

也就是说,默认情况下,任何对象之间使用equals方法进行比较,比较的是两者之间的地址是否相同,和“==”的作用一模一样:

public class Fruit {

    private String name;
    private Integer weight;

    public Fruit(){}

    public Fruit(String name, Integer weight){
        this.name = name;
        this.weight = weight;
    }

    // setters and getters...
    public static void main(String[] args) throws Exception {

        Fruit apple1 = new Fruit("apple",13);
        Fruit apple2 = new Fruit("apple",13);

        // print false
        System.out.println(apple1.equals(apple2));
        // print false
        System.out.println(apple1 == apple2);
    }

那么如何才能使用equals方法来比较两个对象之间的内容是否相等呢?这个其实在我们日常使用的String和Integer中已经实现了的。

public static void main(String[] args) throws Exception {

        String s1 = new String("zhangsan");
        String s2 = new String("zhangsan");
        String s3 = new String("lisi");

        // print true
        System.out.println(s1.equals(s2));
        // print false
        System.out.println(s1 == s2);
        // print false
        System.out.println(s1.equals(s3));

        Integer t1 = new Integer(10);
        Integer t2 = new Integer(10);
        Integer t3 = new Integer(1);

        // print true
        System.out.println(t1.equals(t2));
        // print false
        System.out.println(t1 == t2);
        // print false
        System.out.println(t1.equals(t3));
    }

为什么String和Integer就可以做到比较的是内容,而不是存放内容的地址呢?我们来看下它们的源码是怎么实现的:

    // String源码中的equals方法实现
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
    // Integer源码中equals方法实现
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

如此,我们得出结论,想要通过equals方法来比较两个对象的内容是否相等,是需要重写从Object中继承而来的equals方法的,如果不重写,那么默认就是比较的两个对象的地址。

我们在刚才的Fruit中增加equals的重写,这个使用IDE可以自动生成:

public class Fruit {

    private String name;
    private Integer weight;

    public Fruit(){}

    public Fruit(String name, Integer weight){
        this.name = name;
        this.weight = weight;
    }

    @Override
    public boolean equals(Object o) {
        // 被比较对象等同自身则返回true
        if (this == o) return true;
        // 被比较对象等于null或者两个根本是不同的类型则返回false
        if (o == null || getClass() != o.getClass()) return false;
        // 将被比较对象强制转成相同的类型
        Fruit fruit = (Fruit) o;
        // 将对象中的各个属性依次进行比较,都相同的情况下才返回true
        return Objects.equals(name, fruit.name) &&
                Objects.equals(weight, fruit.weight);
    }

    // setters and getters...
    public static void main(String[] args) throws Exception {

        Fruit apple1 = new Fruit("apple",13);
        Fruit apple2 = new Fruit("apple",13);

        // print true
        System.out.println(apple1.equals(apple2));
        // print false
        System.out.println(apple1 == apple2);

    }

重写后的对象使用equals方法就比较的是两个对象的内容了。

PS:
如上重写的equals中,使用了Objects工具类的equals方法,两个比较的属性是否相等需要取决于属性自身是否重写自身的equals方法。如下是相关的源码:

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

猜你喜欢

热点阅读