最近看到一个网友关于==和equals 做的总结,收获颇多,在此我也谈谈自己的一些见解:
java中equals方法和“==”的区别:
equals 方法是 java.lang.Object 类的方法。
有两种用法说明:
(1)对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,其比较方法不同。
a) “==”比较两个变量本身的值,即两个对象在内存中的首地址。
b) “equals()”比较字符串中所包含的内容是否相同。
比如:
String s1,s2,s3 = "abc", s4 ="abc" ;
s1 = new String("abc");
s2 = new String("abc");
那么:
s3==s4; ------ true
s1==s2 ; ------ false
s1.equals(s2) ; ------true
解释:
背景知识:在JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。例如:String a="abc";,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc”的这么一个对象,判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。
字符串对象的创建由于字符串对象的大量使用[它是一个对象,一般而言对象总是在heap分配内存],Java中为了节省内存空间和运行时间[如比较字符串时,==比equals()快],在编译阶段就把所有的字符串文字放到一个文字池中,而运行时文字池成为常量池的一部分。文字池的好处,就是该池中所有相同的字符串常量被合并,只占用一个空间。我们知道,对两个引用变量,使用==判断它们的值[引用]是否相等,即指向同一个对象。
分析:好了,现在我们来分析上面的代码:变量s3和s4是指向栈中的同一个对象的,该对象在字符串池中,同一个对象的地址肯定是相同的,故s3==s4是正确的;而对于s1 = new String("abc");这里"abc"本身就是pool中的一个对象,而在运行时执行new String()时,将pool中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s1持有,ok,这条语句就创建了2个String对象。而s1是指向heap中的对象的。同理,对于s2,它也是指向由栈中"abc"对象复制到heap中的一个对象。
好了,现在我们知道s1和s2分别引用的对象都为栈中对象的拷贝,但这两个拷贝在内存堆中有各种的地址,故s1==s2是错误的。
而对于s1.equals(s2)语句,它是比较s1和s2所引用对象的值是否相等,显然他们对象的值都是"abc",故s1.equals(s2) 正确。
注意:如果: StringBuffer s1 = new StringBuffer("a");
StringBuffer s2 = new StringBuffer("a");
则s1.equals(s2);-------false
因为StringBuffer类中没有重新定义equals这个方法,因此这个方法就来自Object类,而Object类中的equals方法是用来比较“地址”的,所以等于false.
(2)对于非字符串变量来说,"=="和"equals"方法的作用是相同的都是用来比较其对象在堆内存的首地址,即用来比较两个引用变量是否指向同一个对象。
比如:
class A
{
A obj1 = new A();
A obj2 = new A();
}
则 obj1==obj2; -----------false
obj1.equals(obj2);-----------false
但是如加上这样一句:obj1=obj2;
则 obj1==obj2; -----------true
obj1.equals(obj2); ----------true
总之:equals方法对于字符串来说是比较内容的,而对于非字符串来说是比较其指向的对象是否相同的。
== 比较符也是比较指向的对象是否相同的也就是对象在对内存中的的首地址。
String类中重新定义了equals这个方法,而且比较的是值,而不是地址。
//END