== 和 equals的区别
前言
相信很多兄弟们在面试的过程中有被面试官问过:“==”和equals有什么区别?
KK最开始自己的回答是:"=="比较的地址值,equals比较的是实际的值。当然了,最后的面试结果肯定是不理想的(还是KK自己太菜了)。面试结束后,我就开始上网浏览相关的文章,现在才算是对这俩玩意有了一个相较而言清晰的认知。让我们开始吧!
==
首先需要提一下Java基础中的数据类型。Java中包含了8中基本数据类型以及无数的引用数据类型。其中基本数据类型包括:byte、short、int、long、boolean、float、double、char
先来看一段代码:
int i = 1;
int j = 1;
String x = new String("Hello Word");
String y = new String("Hello Word");
System.out.println(x == y); // false
System.out.println(i == j); // true
int类型的比较的结果是true(int只是举例,其他基本数据类型得到的结果和int相同),String类型的比较的结果是false。开始不是说"=="比较的不是地址值么?
其实是这样的,基本数据类型中"=="比较的是数值,引用数据类型比较的是地址值。
上述代码中,在申明两个String类型的对象之后,两个String类型的对象引用分别指向堆内存中不同的地址值,所以比较结果是false。然而基本数据类型比较的值,所以结果为true。😀
有的同志们就要问了,我平时申明一个字符串的时候从来都是这么写的,代码如下:
String x = "Hello Word";
String y = "Hello Word";
System.out.println(x == y); // true
这个时候的结果为什么又是true了?String不是引用数据类型么?引用数据类型比较的不是地址值么?KK你不是搁着扯犊子呢么?
上述代码中,其实在申明第一个字符串的时候,字符串是存在JVM的常量池中的,在申明第二个字符串的时候,Jvm发现,这个“Hello Word”在我的常量池中已经存在了,直接让第二个变量引用它就好了。这时候两个String的变量引用的是一个地址值,结果当然是true了。
所以“==”在比较引用数据类型的时候比较的是地址值是没有错滴。
equals
首先我们知道所有类的equals方法继承于顶级父类Object,我们先来看看Object类中的equals方法
public class Object {
...
public boolean equals(Object obj) {
return (this == obj);
}
}
看!Object中的equals方法比较的是地址值!并不是比较真实的值。所以equals方法到底比较的是什么?
Java中类都是继承于Object类。每个类都会将Object类中equals方法继承过来。如果一个类没有重写equals方法,那么在使用equals方法的过程中还是比较的是地址值。
如果重写了!例如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自己重写的equals方法,它比较的就是值,并非地址值。
我们再来看下int类型的包装类Integer的equals方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Integer中equals方法调用了intValue()方法,比较也并非是地址值而是值
总结
上面这一堆最后KK得出来的结论就是
1.“==”在比较基本数据类型的时候比较的值,在比较引用数据类型的时候比较的是地址值
2.equals方法,如果当前类没有重写Object类中的equals(),那么比较的就是地址值。如果重写了equals方法,实现了值的比较,那么就是比较的是值。例如String类和Integer类。
如果各位兄弟们发现KK有哪些地方写的不对,欢迎批评指正与交流,收工!
题外话
写完上面这些内容的时候,KK想到了一个比较经典的题目,也算是自己也重新回顾记录一下。
Integer i = 127;
Integer j = 127;
Integer x = 128;
Integer y = 128;
System.out.println(i == j); // true
System.out.println(x == y); // false
为什么第一个比较的结果是true,第二个false?如果说“==”比较的都是地址值,那么结果要么都是true,要么都是false。为什么会有不一样的结果?
让我们反编译下代码就明了了
我们可以看到,在申明Integer变量的时候,实际上是执行了自动装箱的过程,也即是Integer.valueOf ();
我们来看下valueOf的源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
注释就不放进来了,KK简单说下大致意思,就是-128 到 127之间的数值在Integer中是有一个静态数组进行缓存的,如果传进的数值刚好 >= -128 并且 <= 127 ,会直接返回静态数组中的的Integer对象,否则就返回一个新的Integer对象。
我们知道在Java中被static修饰的,在JVM中就是唯一的,所以当声明两个Integer 类型的127时,其实自动装箱的返回的结果是同一个Integer对象,所以通过“==”得到的结果是true。
如果声明的Integer类型超过127或者比-128小,就会返回新的Integer对象。这样上面的代码是不是就解释的通了。
参考文章
https://www.cnblogs.com/dolphin0520/p/3592500.html
https://www.cnblogs.com/wang-yaz/p/8516151.html