equals如果没有被重写的话,和==的作用是一样的,都是判断两个对象引用是否指向同一个地址。一般重写了equals()方法就表示比较它们“实际意义上相等”,比较的是内容,而不是引用地址。Java中String重写了equals方法,所以此时比较的是两者的内容是否相等,而==比较的永远是地址。
package testPage; /*
* ==和equals有何区别
* 这是在网上偶然看到的一个帖子,如果让我说,还真说不清楚,所以决定一探究竟。
*
*/ public class StringAndEquals { public static void main(String[] args) {
// 案例1
String a = "abc";
String b = "abc";
System.out.println("a==b的结果是:" + (a == b)); // 结果:true
System.out.println("a.equals(b)的结果是" + (a.equals(b))); // 结果:true // 案例2
String c = new String("abc");
String d = new String("abc");
System.out.println("c==d的结果是:" + (c == d)); // 结果:false
System.out.println("c.equals(d)的结果是" + (c.equals(d))); // 结果:true // 案例3
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2) {
System.out.println("s1 == s2");
} else {
System.out.println("s1 != s2"); // 输出这句话
}
if (s1.equals(s2)) {
System.out.println("s1 equals s2"); // 输出这句话
} else {
System.out.println("s1 not equals s2");
} // 案例4
String s3 = "Monday";
String s4 = new String("Monday");
s4 = s4.intern();
if (s3 == s4) {
System.out.println("s3 == s4"); // 输出这句话
} else {
System.out.println("s3 != s4");
}
if (s1.equals(s4)) {
System.out.println("s3 equals s4"); // 输出这句话
} else {
System.out.println("s3 not equals s4");
} } }
对于案例1,在内存堆中还有个东西就“串池”,当你以赋值的形式,即String a = "abc";给a赋值,系统会先在“串池”里找有没有,没有就创建,如果有,就直接给赋值了。在这里例子中String a = "abc",之前“串池”中没有,于是系统创建了一个,String b = "abc"到“串池”中寻找的时候,有了,于是直接赋与内存地址,因此输出为true。
对于案例2,直接new出来的字符串不在“串池”中,因此每次new的是不“==”的。
对于案例3,结合前两个案例的解析,很容易开出原因。
对于案例4,加入了inter()方法,intern()后字符串可以直接 == 进行比较,速度提高了3倍。java.lang.String的intern()方法"abc".intern()方法的返回值还是字符串"abc",表面上看起来好像这个方法没什么用处。但实际上,它做了个小动作:检查字符串池里是否存在"abc"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会 把"abc"添加到字符串池中,然后再返回它的引用。
我们清楚了用法之后,看一下原理吧,首先是equals的源码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
}
如果重写了equals方法,比如String类中的equals方法,源码如下:
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count; // 这里的count是事先定义的一个属性,初始值为字符串的size
if (n == anotherString.count) {
char v1[] = value; // value为字符串转化的字符数组
char v2[] = anotherString.value;
int i = offset; // offset默认为0
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
从上面的代码,我们可以这样其实在地址不相等的情况下会继续比较值,如果值相等,返回true。而==返回的结果和重不重写equals没关系,重写equals只会对Object.equals(Object)的结果造成影响。
所以,总的来说,我们可以得到下面的结论:
java中的数据类型,可分为两类:
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。
2.复合数据类型(类)
当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
参考资料:
http://bbs.csdn.net/topics/300179403
http://www.cnblogs.com/zhxhdean/archive/2011/03/25/1995431.html
http://geyubin.iteye.com/blog/1145464