equals与“==”之惑
Java中存在两种判断相等的方式,一个采用运算符“==”进行判断,另一个是采用equals方法进行判断。一直对这两种判断方式感到十分迷惑,最近有空好好研究了一番。
“==”操作符比较的是两个变量的值是否相等,对于对象的引用则表示的是对象在堆中存储的地址是否相等。
equals方法是Object的一个方法,对于没有重写这个方法的类来说,equals方法的作用和“==”是一样的,因为这个方法就是用“==”来实现的。对于重写了这个方法(Java Api中的绝大部分类也这么做了)的类来说,那么功能就与“==”不同了,一般来说,equals方法表示的是两个引用是否是同一个对象的引用,即比较的是对象的内容是否相同。
下面,分类型来说说“==”与equals方法的用法。
1、 简单基本类型之间的比较
对于简单基本类型之间的比较来说,只能使用“==”运算符,其含义也是显而易见的,就是比较两个值是否相等,在此不多做解释。
2、 简单对象之间的比较
此处的简单对象指的是那些自定义的,但是未重写equals方法的类的实例。对于这类的equals方法的作用是与“==”相同的,比较的是两个对象的地址是否相同。下面是我写的测试代码:
publicclass Test1 {
}
publicclass Test2 {
publicstaticvoid main(String[] args) {
Object obj1 = new Object();
Object obj2 = obj1;
Object obj3 = new Object();
System.out.println("obj1 == obj2: " + (obj1 == obj2));
System.out.println("obj1.equals(obj2): " + obj1.equals(obj2));
System.out.println("obj1 == obj3: " + (obj1 == obj3));
System.out.println("obj1.equals(obj3): " + obj1.equals(obj3));
Test1 test11 = new Test1();
Test1 test12 = test11;
Test1 test13 = new Test1();
System.out.println("test11 == test12: " + (test11 == test12));
System.out.println("test11.equals(test12): " + test11.equals(test12));
System.out.println("test11 == test13: " + (test11 == test13));
System.out.println("test11.equals(test13): " + test11.equals(test13));
}
}
输出结果为
obj1 == obj2: true
obj1.equals(obj2): true
obj1 == obj3: false
obj1.equals(obj3): false
test11 == test12: true
test11.equals(test12): true
test11 == test13: false
test11.equals(test13): false
从中可以看出obj1与obj2、obj1与obj3和test11与test12、test11与test13的比较结果是一样的,而且equals方法与“==”的比较结果是一样的。
3、 String类型的比较
对于String对象的equals方法比较的就是两个对象的内容是否相同,而“==”比较的依旧是两对象的地址是否相同。
publicclass Test1 {
publicstaticvoid main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
String s3 = new String("Monday");
System.out.println("s1 == s2: " + (s1 == s2));
System.out.println("s1.equals(s2): " + s1.equals(s2));
System.out.println("s1 == s3: " + (s1 == s3));
System.out.println("s1.equals(s3): " + s1.equals(s3));
s3 = s3.intern();
System.out.println("after s3.intern()");
System.out.println("s1 == s3: " + (s1 == s3));
System.out.println("s1.equals(s3): " + s1.equals(s3));
}
}
输出结果为:
s1 == s2: true
s1.equals(s2): true
s1 == s3: false
s1.equals(s3): true
s1 == s3: true
s1.equals(s3): true
从结果来看,s1和s2应该引用的是同一个对象。原因是程序在运行的时候会创建一个字符串缓冲池,当使用String s1 = "Monday"创建对象时,程序会将s1放入到缓冲池中,而再用String s2 = "Monday"创建对象时,程序会首先查找池中的对象是否存在相同值的,如果存在,就返回池中对象的引用,不存在,则新建一个对象放入池中,并返回对象,这里显然返回的是s1创建的对象的应用,因此,第一行结果为true。又因为String的equals方法比较的是内容,所以第二行的结果也是true。当使用String s3 = new String("Monday")创建对象时,是告诉程序不使用池中的具有相同内容的对象,直接新建一个对象,因此第三行为false,第四行为true,但是当执行s3.intern()后,程序会检查池中是否存在相同内容的对象,如果存在,则返回该对象的引用,如果不存在,则将对象放入池中,并返回该对象的引用,因此第五行和第六行都是true。
4、 简单基本类型与封装类之间的比较
在这里,以int和Integer为例进行说明。在jdk1.5以上的版本中基本类型与封装类型能够互相转化,与String类型的对象和字符串常量之间的比较类似。
测试代码如下:
publicclass Test1 {
publicstaticvoid main(String[] args) {
int i = 1;
Integer i1 = 1;
Integer i2 = 1;
Integer i3 = new Integer(1);
Integer i4 = new Integer(1);
System.out.println("i1 == i2: " + (i1 == i2));
System.out.println("i1.equals(i2): " + i1.equals(i2));
System.out.println();
System.out.println("i3 == i4: " + (i3 == i4));
System.out.println("i3.equals(i4): " + i3.equals(i4));
System.out.println();
System.out.println("i2 == i4: " + (i2 == i4));
System.out.println("i2.equals(i4): " + i2.equals(i4));
System.out.println();
System.out.println("i == i2: " + (i == i2));
System.out.println("i2.equals(i): " + i2.equals(i));
System.out.println();
System.out.println("i == i4: " + (i == i4));
System.out.println("i4.equals(i): " + i4.equals(i));
}
}
输出结果为:
i1 == i2: true
i1.equals(i2): true
i3 == i4: false
i3.equals(i4): true
i2 == i4: false
i2.equals(i4): true
i == i2: true
i2.equals(i): true
i == i4: true
i4.equals(i): true
第一行和第二行说明,i1和i2是引用了同一个对象,而且内容也相同。第三行和第四行说明i3和i4引用了不同的对象,但是内容是相同的。第五行和第六行说明i2和i4引用了不同的对象,但是内容是相同的。第七行和第八行说明经过i经过转型之后引用了i2引用的对象,而且内容相同。第九行和第十行,同样说明了经过i经过转型之后引用了i4引用的对象,而且内容相同。但是从第五行和第六行来看,i2和i4是不同的对象,我的猜测是i在转型过程中引用了“==”右边引用的对象,看起来挺神奇的。
好了,关于equals和“==”的研究就暂时先告一段落吧~~不对的地方请多多指正啊。