注:比较运算符== :两个字符串的地址是否相同。
情景1:
String str1 ="hello world";
Stringstr2 ="hello world";
System.out.println("(str1 == str2)? "+ (str1 == str2));
结果:true
String常量池
Java中的常量池技术是为了方便快捷地创建某些对象而出现的,当需要一个对象时,便可从池中取一个出来(若池中没有则创建该对象),所以在需要重复创建相等变量时节省了许多时间。常量池实际也是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。在class文件中有一部分来存储编译期间生成的字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。
因此String str1 = "helloworld"; 和 String str2 = "hello world"; 都在编译期间生成了字面常量和符号引用,运行期间字面常量"helloworld"被存储在运行时常量池(当然只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。
str1与str2指向常量池同一存储空间,所以为true。
情景2:
Stringstr3 =newString("hello world");
Stringstr4 =newString("hello world");
System.out.println("(str3 == str4)? "+ (str3 == str4));
结果:false
通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。
情景3:
Stringstr1 ="hello world";
Stringstr3 =newString("hello world");
System.out.println("(str1 == str3)? " + (str1 == str3));
结果:false
1) 栈中开辟一块空间存放引用str1;
2) String池中开辟一块空间,存放String常量"hello world";
3) 引用str1指向池中String常量"hello world",指代的地址即常量"hello world"所在地址;
4) 栈中开辟一块空间存放引用str3;
5) 堆中开辟一块空间存放一个新建的String对象"hello world";
6) 引用str3指向堆中的新建的String对象"hello world";
7) str3所指代的对象地址为堆中地址,而str1地址在池中,输出为false;
情景4:
String str4 = new String("hello world");
Stringstr5 = str4;
System.out.println("(str4 == str5)? " + (str4 == str5));
结果:true
1) 栈中开辟一块空间存放引用str4;
2) 堆中开辟一块空间存放一个新建的String对象" hello world";
3) 引用str4指向堆中的新建的String对象"abc";
4) 栈中开辟一块空间存放引用str5;
5) 引用str5指向引用str4;
6) str4,str5所指代的对象地址为堆中地址,且相等,故为true;