到底创建了几个字符串对象

首先,JDK1.7之后,常量池和静态变量从方法区中移到了堆里面,至于JDK1.8之后方法区被改为元空间这是后话。这里有一个容易混淆的地方。

String str = "abc";

这我们都知道句话是在常量池中创建了一个对象,容易混淆的是"abc"这个字符串对象是被创建在常量池中,并不是直接在堆中,只不过常量池在堆中而已。如果用new直接创建一个对象,是直接创建在堆中,即新生代的Eden区域。所以,

String str = new String("abc");

我们都知道这句话是创建了两个对象,了解更细一点是,一个是在常量池中的"abc",另一个是在Eden区域的new String(),只不过堆中的这个对象是从常量池中复制过来的。还可以再深究一点,

String str1 = new String("abc");
String str2 = new String("abc");

这两句话一共创建了三个对象,很好理解。因为常量池一个好处就是相同的常量可以合并为一个对象,即相同的字符串在常量池中是一个对象,但是在堆中两次new创建的对象,尽管都是复制的常量池中同一个字符串对象,但它们是两个不同的对象,所以这里有三个对象被创建,一个是常量池中的"abc",还有两个是new在Eden区域的对象,如果更严谨一点,要看常量池中的"abc"是不是之前创建过,如果创建过,就只新建了两个对象。那思考一个问题,我们都知道对象的equals()比较的是两个对象是否为同一个对象,那照这么说str1.equals(str2)岂不是应该为false?其实不是的,str1.equals(str2)为true。

这里有一个重要的地方,因为String对象的equals()方法是被重写过的,重写后比较的是String对象的值,即使str1和str2不是同一个对象,但是他们都是复制的同一个常量池中字符串对象"abc",值相同,所以str1.equals(str2)为true。JAVA中除了String,Date类型对象的equals()方法也是被重写过的。而其他引用类型对象的equals()方法比较的为是否是同一个对象。

所以有时候会出现这种情况,一般引用类型的equals()方法和==方法比较的结果都一致,但是String和Date类型不一定,因为如果两个不同的String或者Date类型对象,他们值相同,equals()方法比较自然是true,但是由于是不同的对象,==用于对象间比较的时候比较的是地址值是否相同,所以==比较结果自然是false。

顺便总结一下equals()和==的区别:

关于.equals()方法只能用于比较对象再补充一个需要注意的地方

Integer a = 1;
int b = 1;
a.equals(b)

这里a.equals(b)为true,虽然equals(Object obj)传参为对象,这里会给b自动装箱。

猜你喜欢

转载自blog.csdn.net/weixin_42447959/article/details/84111902