在讲 == 与 equals 之前,不妨先做一道题,看下下面这段代码的输出结果是什么?
/**
* @author Woo_home
* @create by 2020/3/18
*/
class Student {
private String name;
public Student(String name) {
this.name = name;
}
}
public class TestEquals {
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
Set<String> stringSet = new HashSet<>();
stringSet.add(s1);
stringSet.add(s2);
System.out.println(stringSet.size());
System.out.println("--------------------------");
Student student1 = new Student("abc");
Student student2 = new Student("abc");
System.out.println(student1 == student2);
System.out.println(student1.equals(student2));
Set<Student> studentSet = new HashSet<>();
studentSet.add(student1);
studentSet.add(student2);
System.out.println(studentSet.size());
}
}
OK,相信你们都已经做出来了,来对下答案,如下:
虚线以上的相信大部分人都能作对,但是虚线以下的就会有点不一样了。一开始我也做错了虚线以下的,那么就来探个究竟
==
先看下下面这个代码,== 即可以比较基本类型也可以比较引用类型。如果比较基本类型,如果比较的是基本类型,则比较的是值是否相等;如果比较的是引用类型,则比较的是地址是否相等
再来看下下面这段代码,new 出来的肯定是引用类型,存放在堆里
既然是在堆里的就不能跟同一个对象共用一个地址,所以下面这段代码输出的是 false
equals()
equals() 是 Object 类的方法,因为 Object 是所有类的父类,也就是说在 Java 里面任何一个类都有 equals() 方法
那么坦白地说 equals() 比较什么呢?
答案是:不一定
那么如果是面试被问到 equals 比较什么怎么回答呢?
- 看 equals() 是否被重写过,如果没有被重写过,则这个 equals 就想等于 = =,重写过后要具体问题具体分析。如下图是 Object 的 equals() 的源码,可以发现 Object 的 equals() 方法使用的是 ==
那么下面这段代码的就很好理解了,我们点击 equals() 方法跳转的是 Object 的equals() 方法。因为我们的 Student 类并没有重写 Object 的 equals 方法,所以相当于使用了 == ,所以输出的是 false
上面那个好理解,那么下面这个为什么输出的是 true 呢?同样地,我们点击 equals() 方法的源码
跳转的是 String 重写 Object 的 equals() 方法
HashSet 的 add() 方法
OK,前面两个都搞懂了,还有 HashSet 的,下面的代码一个输出是 1,一个输出是 2
关于 HashSet 不会的朋友请看这里 深入理解 HashSet,关于 HashSet 看过这篇文章的朋友都知道,HashSet 底层其实是 HashMap,而且 HashSet 是不会存储相同的元素的。由于 HashSet 底层使用的是 HashMap,所以我们也可以知道 HashSet 的 add 是调用 HashMap 的 put 方法,如下:
那么问题来了,HashMap 我们都知道是一个 Key、Value 类型的一个类,需要传入两个东东,而 HashSet 是 add 单个东东。数量不匹配,这怎么实现的呢?
从 HashSet 的 add() 方法我们可以发现,传入的对象就是 HashMap 的 Key,而 Value 则是一个 Object 对象,也就是说 Value 不是很重要,重要的是 Key
由于 HashSet 是不允许存储重复的元素的(会被覆盖掉),那么 HashSet 是怎么判断 add 的是不是同一个对象呢?
靠的是 hashCode 的值
因为 String 重写了 hashCode() 的方法,所以先看下 String 的 hashCode() 方法
而 Student 这个类并没有,而是使用父类 Object 的 hashCode() 方法,如下:
那么这就很简单了,原来 HashSet 不允许出现重复元素是根据 hashCode() 来区分的,那么我们也将上述代码打印成 hashCode() 对比下
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.hashCode() + "\t" + s2.hashCode());
Student student1 = new Student("abc");
Student student2 = new Student("abc");
System.out.println(student1.hashCode() + "\t" + student2.hashCode());
输出: