 到底有什么区别?一文彻底搞懂!)
学习 Java 时几乎每个人都会遇到这样一道经典面试题Java 中和equals()有什么区别很多初学者都会回答“比较地址equals()比较内容。”这句话虽然对但并不完整甚至在某些情况下还是错的。今天我们就从零开始把这个问题彻底讲明白。一、什么是是 Java 的一个比较运算符。它既可以比较基本数据类型也可以比较引用类型但比较规则不同。1、比较基本数据类型对于基本数据类型int、double、char、boolean等比较的是值是否相等。例如inta10;intb10;System.out.println(ab);输出true因为a 的值10 b 的值10两个值相同所以返回true。再例如doublex3.14;doubley3.14;System.out.println(xy);结果仍然是true因此基本数据类型使用比较的是值。2、比较引用类型对于对象来说比较的是两个引用是否指向同一个对象。例如Strings1newString(Java);Strings2newString(Java);System.out.println(s1s2);输出false为什么因为内存中实际上创建了两个对象。堆内存 ------------- s1 --| Java | ------------- ------------- s2 --| Java | -------------虽然内容一样但它们是两个不同的对象。所以s1 s2比较的是两个引用是否指向同一个对象答案是不是因此返回false所以引用类型使用比较的是对象地址更准确地说是比较引用是否指向同一个对象。二、什么是equals()equals()是Object类中的一个方法。源码如下publicbooleanequals(Objectobj){return(thisobj);}可以发现Object 默认实现的equals()本质上还是使用。也就是说默认情况下obj1.equals(obj2)等价于obj1obj2因此如果一个类没有重写equals()那么equals()和的效果完全一样。三、为什么还要有equals()因为很多时候我们更关心的是内容是否相同而不是是不是同一个对象例如Strings1newString(Java);Strings2newString(Java);虽然s1和s2不是同一个对象。但是字符串内容都是 Java。这时候System.out.println(s1.equals(s2));输出true为什么因为String类重写了equals()方法。源码思想可以简化理解为publicbooleanequals(Objectobj){比较两个字符串长度 再比较每一个字符 全部相同返回true}因此Java 和 Java内容一样所以返回true四、什么时候和equals()结果不同来看一个经典例子。Strings1newString(abc);Strings2newString(abc);System.out.println(s1s2);System.out.println(s1.equals(s2));输出false true为什么比较的是是不是同一个对象答案不是。所以falseequals()比较的是字符串内容是否相同答案都是 abc。所以true这也是 Java 面试最经典的一道题。五、为什么有时候又是 true例如Strings1Java;Strings2Java;System.out.println(s1s2);输出true很多初学者会疑惑不是说比较地址吗为什么这里又是true原因是Java 有字符串常量池String Pool。当写Strings1Java;Strings2Java;实际上字符串常量池 --------- | Java | --------- ↑ ↑ s1 s2两个变量都指向常量池中的同一个字符串对象。因此s1 s2结果就是true如果使用newString(Java)就会重新创建对象。因此Strings1newString(Java);Strings2newString(Java);内存变成堆 -------- -------- | Java | | Java | -------- -------- ↑ ↑ s1 s2自然s1 s2就是false六、自定义对象为什么 equals() 还是 false例如classStudent{Stringname;Student(Stringname){this.namename;}}创建两个对象Students1newStudent(Tom);Students2newStudent(Tom);System.out.println(s1.equals(s2));输出false为什么因为Student 没有重写equals()。它继承的是Object.equals()而Object.equals()底层就是thisobj比较地址。因此false七、如何让 equals() 比较内容只需要重写equals()。例如importjava.util.Objects;classStudent{Stringname;Student(Stringname){this.namename;}Overridepublicbooleanequals(Objectobj){if(thisobj){returntrue;}if(objnull||getClass()!obj.getClass()){returnfalse;}Studentother(Student)obj;returnObjects.equals(name,other.name);}}现在Students1newStudent(Tom);Students2newStudent(Tom);System.out.println(s1.equals(s2));输出true因为现在比较的是name 是否相同。这也是实际开发中最常见的做法。八、为什么重写 equals() 通常还要重写 hashCode()这是很多面试都会追问的问题。例如HashSetStudentsetnewHashSet();如果两个对象equals()返回true但是hashCode()不同。那么HashSet 仍然可能把它们当成两个不同对象。因此 Java 官方规定如果重写了 equals()通常也必须重写 hashCode()保证相等对象具有相同的哈希值。IDE如 IntelliJ IDEA通常也会提示同时生成这两个方法。九、面试怎么回答如果面试官问Java 中和equals()有什么区别可以这样回答是比较运算符。对于基本数据类型它比较的是值对于引用类型它比较的是两个引用是否指向同一个对象。equals()是Object类的方法默认实现也是比较引用但很多类例如 String、Integer、自定义实体类都会重写equals()用于比较对象内容是否相等。因此是否比较内容取决于该类是否重写了equals()方法。这是比较标准、完整的面试回答。十、总结最后用一张表总结比较方式基本数据类型引用类型比较值比较是否指向同一个对象equals()不适用基本类型不能调用方法默认比较引用重写后通常比较内容记住下面四句话即可比较基本类型时比较值。比较对象时比较引用是否指向同一个对象。equals()默认和一样因为 Object 的实现本质就是。很多类如 String重写了equals()因此equals()往往用于比较对象内容。一句话总结是 Java 的比较运算符比较值或对象引用equals()是对象的方法默认比较引用但重写后通常用于比较对象内容是否相等。