Java基础之==与equals
1. 使用 ==
1.1 基本类型比较
int a = 1;
int b = 1;
byte c = 1;
Integer d1 = new Integer(1);
Integer d2 = new Integer(1);
System.out.println(a == b);
//结果:true
System.out.println(a == c);
//结果:true
System.out.println(a == d1);
//结果:true
System.out.println(d2 == a);
//结果:true
System.out.println(d1 == d2);
//结果:false
java中的基本类型,包含:int、long、short、byte、char、boolean、float、double这8种,可以使用==号判断值是否相等。
如果出现了基本类型的包装类,比如:Integer,用一个基本类型和一个包装类,使用号也能正确判断(a == d1),返回true,因为Integer和int比较时,会自动拆箱,这是比较值是否相等。
但如果有两个包装类(d1 == d2),使用==号判断的结果可能是false,因为两个Integer比较时,比较的是它们指向的引用(即内存地址)是否相等。
Integer d3 = 1;
Integer d4 = 1;
Integer d5 = 128;
Integer d6 = 128;
System.out.println(d3 == d4);
//结果:true
System.out.println(d5 == d6);
//结果:false
为什么结果不一样呢
答:因为Integer有一个常量池,-128~127直接的Integer数据直接缓存进入常量池。所以1在常量池,而128不在。
new的Integer对象不适用常量池(如d1 == d2)
1.2 字符串比较
String e = "abc";
String f = "abc";
String g = new String("abc");
String h = new String("abc");
System.out.println(e == f);
//结果:true
System.out.println(e == g);
//结果:false
System.out.println(g == h);
//结果:false
普通的字符串变量,使用==号判断,也能返回正确的结果。
但如果一个普通的字符串变量,跟new出来的字符串对象使用 == 号判断时,返回false。这一点,跟之前说过的用一个基本类型和一个包装类,使用 == 号判断的结果有区别,字符串没有自动拆箱的功能,这一点需要特别注意。
此外,两个new出来的字符串对象使用 == 号判断时,也返回false,因为他们比较比较的两个对象的内存地址,而不是内存地址所存放的值。
总结:使用 == 号,可以非常快速判断8种基本数据类型是否相等,除此之外,还能判断两个对象的引用是否相等。
2. 使用equals方法
那怎么判断两个new对象的值是否相等呢?
答:使用equals方法。
equals方法其实是Object类中的方法:只判断两个对象的引用是否相等。
public boolean equals(Object obj) {
return (this == obj);
}
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;
}
它依然会先判断两个对象引用是否相等,如果相等返回true。接下来,会把两个字符串的挨个字符进行比较,只有所有字符都相等才返回true。
String g = new String("abc");
String h = new String("abc");
System.out.println(g.equals(h));
//结果:true
3. 空指针异常
前两种判断,都可能会报空指针异常。
3.1 ==
int a = 1;
Integer b = new Integer(1);
Integer c = null;
System.out.println(a == b);
//结果:true
System.out.println(a == c);
//结果:NullPointerException
int和Integer使用==号判断是否相等时,Integer会自动拆箱成int。
但由于c在自动拆箱的过程中,需要给它赋值int的默认值0。而给空对象,赋值0,必然会报空指针异常
3.2 equals
String e = null;
String f = "abc";
System.out.println(e.equals(f));
//结果:NullPointerException
System.out.println(f.equals(e));
//false
为什么一个报空指针另一个没有呢?
我们先看源码:
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
Soga
按照equals的逻辑,只把前者为空的情况考虑进去了,这就解释了为什么有两种不同的结果
等等 这里还有个问题,在equals方法里面也使用了 == 为什么不会报空指针异常呢?
答:因为而Objects类的equals方法,使用了Object类型接收参数,它的默认值是null,不用进行类型转换,也不用像int类型对象赋值默认值0。
3.3 解决办法
重写equals:在代码中判空
private static boolean equals(String e, String f) {
if (e == null) {
return f == null;
}
return e.equals(f);
}
4. Object.equals的坑
Integer a = 1;
Integer b = 1;
long c = 1L;
System.out.println(Objects.equals(a, b));
//结果:true
System.out.println(Objects.equals(a, c));
//结果:false
equals(a,c)为什么是false呢?为什么呢?为什么呢?
答:这就要从Integer的equals方法说起了。
它的equals方法具体代码如下:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
先判断参数obj是否是Integer类型,如果不是,则直接返回false。如果是Integer类型,再进一步判断int值是否相等。
而上面这个例子中c是long类型,所以Integer的equals方法直接返回了false。
也就是说,如果调用了Integer的equals方法,必须要求入参也是Integer类型,否则该方法会直接返回false。
原来坑在这里!!!
除此之外,还有Byte、Short、Double、Float、Boolean和Character也有类似的equals方法判断逻辑。即同类型的变量判断等同于==,但是不同类型的就…
那么,如何解决上面的问题呢?
解决1: 强制类型转换
System.out.println(Objects.equals(a, (int)c));
//结果:true
System.out.println(Objects.equals(c, (long)a));
//结果:true
解决2: 用==
System.out.println(a == c);
//结果:true