Java 中的 equals
和 ==
对于不同的数据类型有不同的表现,话不多少,看演示。
对于基本数据类型来说,只能用 ==
,所以毫无疑问,这里是用来判断两个基本数据类型的值是否一致。
先来看看这种创建对象的方式:
public class Demo {
public static void main(String[] args) {
Integer i1 = new Integer(100);
Integer i2 = new Integer(100);
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
}
}
运行结果:
false
true
这里可能会有人疑问,==
不是判断两者是否相等么,那为什么结果为 false
呢?
因为这里的 Integer 是一个对象,也就是引用数据类型,里面存放的是对象在堆内存中的引用值,所以这里的 ==
只是判断两者的引用值是否相同,两者创建了两个对象,在堆内存中分别是不同的引用,由而引用值也不同,才会返回 false
。
那么我们再看一下简化版的 Integer 的创建方式:
package other;
public class Demo {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
Integer i3 = 1000;
Integer i4 = 1000;
System.out.println(i3 == i4);
System.out.println(i3.equals(i4));
}
}
运行结果:
true
true
false
true
equals
毫无疑问是判断值是否相同,所以结果为 true
,但是为什么第一个 ==
又为 true 了呢,而第二个 ==
还是 false。
因为在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。但适用范围只有 -128
到 +127
也就是说当自动装箱时,不会再分配内存空间,而是使用缓存中已存在的对象。
最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size
修改
这种缓存行为不仅适用于 Integer 对象。我们针对所有整数类型的类都有类似的缓存机制。Byte
、Short
、Long
、Character
都支持缓存。
其中 Byte
,Short
,Long
有固定范围: -128 到 127。对于 Character
, 范围是 0 到 127。除了 Integer
可以通过参数改变范围外,其它的都不行。
对于基本数据类型包装类而言,不论是使用哪种方式创建的,判断两者的值是否相同,务必要使用 equals
,而不要使用 ==
。
首先有 Person 类:
public class Person {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
然后示例:
public class Demo {
public static void main(String[] args) {
Person p1 = new Person();
p1.setId(1);
p1.setName("张三");
Person p2 = new Person();
p2.setId(1);
p2.setName("张三");
System.out.println(p1 == p2);
System.out.println(p1.equals(p2));
}
}
这里使用 ==
的结果为 true
很容易理解,毕竟两个对象的引用不同,但是 equals
不是判断值是否相同么,我的两个id
和 name
都是一样的,为什么这里还会返回 false
呢?
Person 中我们没有写 equals 方法,根据 Java 继承的特点,Person 类继承的是 Object,所以使用的是 Object 的 equals 方法,那我们来看看 Object 的 equals 方法是怎么写的。
![image_1bo22o7qv1e801ivjhqftge18d1m.png-24.9kB][1]
原来这里的 equals 方法里用的也是 ==
,那么刚才我们用基本数据类型包装类时,为什么能判断呢,同样,我们找到 Integer 的 equals 方法。
![image_1bo22v5je88n1d611g3la3e1a1m13.png-33kB][2] ![image_1bo2315q517g21glb14ni11c9hdp2n.png-18.8kB][3]
可以看 Integer 的 equals 方法,会先判断该对象是否是一个 Integer 类的一个实例,如果不是则直接返回 false,是的话就比较他们的 value 值是否相等。
所以在我们自定义数据类型时,比较两个对象是否相同,一定要重写 equals 方法。
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
Person p = (Person)obj;
if (this.id == p.id && this.name == p.name) {
return true;
}
}
return false;
}
重写 equals 方法后的运行结果:
false
true
String 也有两种创建方式,一种是 String str = new String("java");
,另一种是 String str = "java"
。
Java 为 String 类型提供了缓冲机制,当使用第二种双引号的形式创建对象时,Java 会先去字符串缓冲池中寻找内容相同的字符串,如果存在就直接拿来应用,如果不存在就创建一个新的字符串放到缓冲池中。对于第一种 new 对象的形式而言,每次都会创建一个新的对象,不会访问字符串缓冲池。
既然如此,对于 String 的 equals
和 ==
你也自然应该明白是什么结果了。
一般情况下,建议使用 String s = "abc"
方式,因为该方式采用的是字符串缓冲池机制,效率更高。
在引用类型中,”==” 是比较两个引用是否指向堆内存里的同一个地址(同一个对象),而 equals 是一个普通的方法,该方法返回的结果依赖于自身的实现。
对于引用类型而言,判断两者是否相同要用 equals
方法,而不是 ==
。当然对于自定义数据类型,记得要重写 equals
方法,不然效果就等同于 ==
了。
[1]: https://cdn.jun6.net/image_1bo22o7qv1e801ivjhqftge18d1m.png
[2]: https://cdn.jun6.net/image_1bo22v5je88n1d611g3la3e1a1m13.png
[3]: https://cdn.jun6.net/image_1bo2315q517g21glb14ni11c9hdp2n.png