先看一段代码:
String test1 = "add";
String test2 = "add";
String test3 = new String("add");
String test4 = new String("add");
System.out.println(test1 == test2);
System.out.println(test1.equals(test2));
System.out.println(test3 == test4);
System.out.println(test3.equals(test4));
System.out.println(test1 == test3);
System.out.println(test1.equals(test4));
运行结果:
true
true
false
true
false
true
分析:
结合上面的语句,我简单说一下字符串的赋值过程。当计算机执行Stringtest1 = "add"的时候,它会先检查内存中是否存在存有“add”的地址空间,如果存在,直接将变量test1指向该地址空间。如果不存在,就新建一块地址空间存放“add”,然后将变量test1指向该地址空间。所以,test1和test2实际上指向的是同一地址空间。当计算机执行Stringtest3 = new String("add")时,它会直接在内存中开辟一块地址空间存放“add”,然后将变量test3指向该地址空间。所以最终的内存分布如下图所示:
结论:
从程序的运行结果和上图来看,我们可以得出:“==”比较的是两个变量的存放地址,只要地址不一样,那它们就是不相等。而“equals”要求的条件就没有那么苛刻,只要值相等了,那它就是true。
继续深入:
让我们来看看对象String的equals方法源码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
从源码中我们可以看到,String类重写了Object类的equals方法,它同样使用“==”进行内存地址的比较,但是String类对比较进行了扩展,使之出现与“==”不同的结果。
扩展:
“==”是基类Object的equal实现,不同的类对它进行了不同的重写,进而导致比较的不同。所以,你完全可以新建一个类,然后重写基类的equals方法,让它按照你自己的方式进行比较。当然,重写equals方法的情况较少,可能我们更多用到的是重写toString方法,但是,他们的原理是一样的。