代码演示:
public class Test { public static void main(String[] args){ // 案例一 String str1 = new String("hello"); String str2 = "hello"; System.out.println(str1 == str2); // false System.out.println(str1.equals(str2)); // true // 案例二 String str3 = "world"; String str4 = "world"; System.out.println(str3 == str4); // true System.out.println(str3.equals(str4)); // true } }
问题说明:
- “ == ” 它的应用场景大致分为两大类,第一类是用来比较基本数据类型的(Java中八大基本数据类型:byte,short,int,float,long,double,char,boolean),在基础数据类型之间他们是直接比较值的。第二类是用来比较对象的,它会直接比较两个对象的内存地址,也就是说,除非两个对象指向同一个地址,否则始终是false.
- equals()方法是Object基类中的方法,所以任何类都会继承这个方法,只是有些类重写了这个方法,就比如String类,我们可以结合String类equals()源码来解释。
// String类中重写的equals()方法 源码: public boolean equals(Object anObject) { if (this == anObject) { // 首先判断是否为同一个对象,若是直接返回true return true; } if (anObject instanceof String) { // 接着判断传进来的是否是String的实例,若是则继续判断 String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { // 首先判断两个字符串的长度,若不是等长直接返回false char v1[] = value; // 字符串的底层是用一个名为value的字符数组来装载数据的。 char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) // 比较每个字符是否相等 return false; i++; } return true; } } return false; }
总结:
- 案例一中,str1和str2是不同的对象,str1通过new关键字来生成对象是在堆区进行的,str2在编译期间生成了 字面常量和符号引用,运行期间字面常量"hello"被存储在运行时常量池(只保存一份)。但是内容相同,因为“==”是比较对象的内存地址的,所以返回false。而重写的equals()方法是比较内容的值的,所以返回true.
- 案例二中,为什么str3和str4用“==”比较会返回true呢?不应该返回false吗?通过在编译期间生成了 字面常量和符号引用将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。所以str3和str4是指向同一个对象的,故返回true。