无论是在面试或者在工作中,==和equals是我们始终无法避免的两个基本使用,但是,==和equals又是不同的,一旦用错了,那么程序就会出现错误,但是排查的时候又很难发现。
我们都知道,Java中有8种基本的数据类型,分别是:Byte,short,int,long,double,folat,boolean,char,其中占一个字节的是byte,short和char占两个字节,int,float占四个字节,double和long占8个字节,boolean只有true和false,这八种数据变量中直接存储数据的值。另外,这8种基本数据类型对应着各自的封装类型,提供了更多的方法,且不进行初始化时值默认为空(基本数据类型必须初始化)。
除此之外,java中还存在着引用数据类型,我们常使用的String就是一种引用类型。
==比较时的作用
简单点说:基础数据类型:==比较的是他们的值是否相等,比如两个int类型的变量,比较的是变量的值是否一样。而引用数据类型:==比较的是引用的地址是否相同,比如说新建了两个对象,比较的是两个对象的地址是否一样。
比如,我们拿int类型和Integer类型来做测试:、
int a = 1;
int b = 2;
int c = 1;
System.out.println("================基本类型=============");
System.out.println(a == c);
System.out.println(a == b);
System.out.println(b == c);
Integer integera = new Integer(1);
Integer integerb = new Integer(1);
Integer integerc = integera;
Integer integerd = new Integer(1);
System.out.println("================引用类型=============");
System.out.println(integera == integerb);
System.out.println(integerb == integerc);
System.out.println(integera == integerc);
System.out.println(integera == integerd);
可以看到输出结果如下:
从这里我们可以看出来,当使用==时,如果是基本类型,直接比较的就是数据的值,因为基本类型保存的就是数据的值,而引用类型保存的是内存中的地址,所以==在比较引用类型时比较的是内存中的地址,可以看到,integera和integerc内存地址相同,此时结果为true,但是,当integera与integerd比较时,虽然两者的值相同,但是引用类型每次new的时候会开辟一片新的区域,所以两者地址是不同的,此时结果为false。
注:我们都知道,引用类型保存的是内存的地址,比如String是不可变的,如果你定义了一个String a = "a";然后令 a = "b",此时改变了String 的内容吗?答案是:没有。因为此时仅仅是在内存中重新开辟了一个区间,修改了a的内存地址,但是原来的“a”依然在内存中存在。那么这个时候又出现一个问题,如果我定义了好几个String类型,他们的值是相同的,这个时候使用==和equals有区别吗?代码如下:
String a = "a";
String b = "a";
String c = new String("a");
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a.equals(c));
System.out.println(a == c);
结果如下:
问题来了,既然String是不可变的,那么a和b应该指向的是不同的地址,为什么使用==和equals都是true呢?原因就是:Java对于字符串序列相同的两个String变量指向的都是同一个地址,也就是说,只要值相同,不管有多少个变量,都指向同一个地址,所以此时无论使用equals和==都是true。那么使用new String 为啥不同呢?因为一旦使用new,那么就相当于重新开辟了内存空间,此时,虽然值相同,但是内存地址不同,所以结果不同
equals比较
当使用equals比较时,equals只能用于封装数据类型,但是并不是说equals只能用于引用数据的比较,equals方法只能由类或者对象去调用,而封装数据类型就是一个类。equals方法如果使用jdk自带的equals方法,那么就只能比较封装数据类型和字符串,如果想要比较对象和其他的object类型,需要重写该方法。
equals比较的两者的内容是否相等,不会比较内存地址。通过查看object类中的equals源码,我们可以发现,其实equals内部使用的依然是==,这里可能很多人会说,两个一样,但是为什么==如果基本类型比较的就是值是否相等,引用类型就比较的是内存地址,而equals单纯的比较的是两者的内容呢?
原因就是,Java重写了object的equals方法,如下,Integer包装类重写的equals方法:
String引用类型中对equals的重写:
通过这里我们就可以看出来,此时比较的只是值了,并不涉及内存地址。所以测试如下:
Integer integera = new Integer(1);
Integer integerb = new Integer(1);
Integer integerc = integera;
Integer integerd = new Integer(1);
System.out.println(integera.equals(integerb));
System.out.println(integera.equals(a));
System.out.println(integerb.equals(integerc));
结果如下:
通过这里我们看出来,即便是不同的内存地址,只要内存地址的内容一样,equals就会返回true,但是,此时使用==会返回false。
如果你想比较两个对象是否相同,那么只能重写equals方法了,否则,无论使用哪一种,返回的都是false,因为他们都是用的==,比较的是地址