JAVA中==与equals的区别
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