Java 面试高频题:== 和 equals 的区别

153 阅读3分钟

大家好我是 Ryanangry,今天来介绍一道常见面试题。面试场上经常遇到面试官问 == 和 equals 有什么区别,这时候有面试经验的小伙伴肯定已经熟烂于心,然而初次遇到这个问题的小伙伴们却多半会答的无厘头。下面我们一起通过源码分析一下这道面试题。

  • == 的含义

首先是基本数据类型, Java 中有八大基本数据类型,分别是 byte,short,int,long,float,double,boolean,char。== 在基本数据类型用使用的时候,直接比较的是变量存储的值是否相等。

其次是引用数据类型, 对于引用数据类型来说,使用 == 比较的是变量的内存地址是否相等。

  • equals 的含义

万物皆对象,首先我们看一下 JDK8 版本 Object 中的 equals 方法是如何定义的

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

可以看出,Object 类中的 equals 方法直接使用了 == 来对两个变量进行比较,也就是默认比较的是内存地址。( 这也是为什么 Java 里推荐我们重写 equals 方法,就是让我们自定义比较规则。)

为了更深入地了解 equals,下面我给大家举个例子。首先新建一个 Book 类,附上三个属性和无参有参构造器,注意我这里没有重写 equals 方法

public class Book{
    private String name;
    private int price;
    
    public Book(){}

    public Book(String name, int price){
        this.name = name;
        this.price = price;
    }
}

创建两本 Book 对象进行比较

public class test {
    public static void main(String[] args) {
        Book book1 = new Book("深入理解 Java 虚拟机", 64.5);
        Book book2 = new Book("深入理解 Java 虚拟机", 64.5);
        System.out.println(book1.equals(book2));    // false
    }
}

可以看出,如果我们没有在 Book 类中重写 Object 中的 equals 方法,那么即使两本书的名字和价格都一样,比较的结果也是 false,原因就是父类 Object 中默认 equals 比较的就是两本 Book 的内存地址

可我就是想让只要 name、price 两个属性值相等的两本书,比较的结果是相等的,该怎么办?

还能怎么办?那就自定义比较规则,重写 equals

public class Book{
    private String name;
    private double price;

    public Book(){}

    public Book(String name, double price){
        this.name = name;
        this.price = price;
    }

    @Override
    public boolean equals(Object obj) {
        // 如果内存地址都相等,那么两本书就是同一本书,一定相等,返回 true
        if(this == obj){
            return true;
        }
        // 判断 obj 是否是 Book 类型
        if(obj instanceof Book){
            // 到这里说明 obj 确实是一本书,强制类型转换
            Book book2 = (Book) obj;
            // 判断属性是否相等,如果都相等就返回 true,否则返回 false
            return this.name.equals(book2.name) && this.price == book2.price;
        }
        // 如果 obj 不是书,那两者一定不相等,返回 false
        return false;
    }
}

先通过 if 条件判断筛选出一些特殊情况,能提高代码执行效率。现在我们再来测试之前的代码,结果会是什么?

public class test {
    public static void main(String[] args) {
        Book book1 = new Book("深入理解 Java 虚拟机", 64.5);
        Book book2 = new Book("深入理解 Java 虚拟机", 64.5);
        System.out.println(book1.equals(book2));    // true
    }
}

意料之中,结果返回 true!

  • 可以看看 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;
}

可以看出 String 类中重写的代码跟我们上面自己重写的代码很相似,先通过 == 判断内存地址是否相等,再判断是否是 String 类型的,层层筛选过后,最后通过遍历 String 底层的 char 数组来判断两个 String 变量的值是否相等。

多阅读源码的好处就是,我们平时的代码规范也可以借鉴这些优秀源码的思想,说不定能让领导大吃一惊哦。现在你学会 == 和 equals 的区别了吗?