简单分析:
String str1= "hello", String str2="he"+"llo";之所以str1==str2返回true是因为两者都是在字符串常量池中(由于初始化就会在此区域分布内存)而常量池中的有个与栈区类似的特性,就是当str2指向的常量在常量区已存在时,他不会创建新的内存空间来存此常量,而是指向已有常量的内存(应该是以此节约空间),此时str1与str2这两个引用变量的值都是存"hello"的内存空间地址,但是String str3= "he"+a;String a="llo";时str1==str3返回的为false,是因为:str1指向的hello在编译期一如既往的还是分配在常量区内,a指向的llo也在常量区,虽然str3也是初始化但是编译器无法判断a这货到底是什么个情况,进而不会将str3的等号右侧声明在常量区内,而是在通过构造时在堆区中的非常量池外的内存中声明,至此str3与str1不止是分配内存的时期不同(一个在编译期,一个在运行期)而且在内存空间的区域也不同,上面最高票答案只区分了时间没区分空间。
总结
String str1 = "hello";这里的str1指的是方法区的字符串常量池中的“hello”,编译时期就知道的; String str2 = "he" + new String("llo");这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。 如果用str1.equal(str2),那么返回的是True;因为两个字符串的内容一样。
注意
str2是一个局部变量,那么存放在栈中,他只是一个指向堆中的那个非常量池中的字符串对象。JVM为了减少字符串对象的重复创建,其维护一个特殊的内存,这段内存被称为字符串常量池。
当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。但是如果是new出来的字符串,那么直接在堆中创建一个字符串对象(运行时创建的)。所以即使
String str9 = new String("hello");//有new就是新的,但是这个是在动态创建的
String str10 = "hello";//这个是在编译的时候就去查找字符串常量池。没有就创建一个。new 出来的就不用去查找直接在堆中动态创建一个新的对象。
String str = "hello"; String str2 = "hel"+"lo";//这个是在编译的时候确定的,会在字符串常量池中创建一个hello对象,然后把对象的引用给str。 System.out.println(str==str2);//true System.out.println(str.equals(str2));//始终比较的是值是否相等返回//true String str3 = "hel"+new String("lo");//这个也是在编译期间确定的,会在字符串常量池中找有没有hello这个对象,有然后把对象的引用给str。此时str == str2返回true; System.out.println(str==str3);//false System.out.println(str.equals(str3));//true String str4 = new String("hello");//new String("llo");这个是在运行的时候确定,所以这个会在堆中的字符创非常量池中去创建一个hello,返回引用,此时str == str3返回的就是false。 System.out.println(str==str4);//false。才堆中存放的对象,只要有new就会是新的创建对象 System.out.println(str.equals(str4));//true String str5 = "hel"+new String("lo");//有new就是新的 String str6 = "hel"+new String("lo");//虽然这两个都是在堆的非常量池中动态创建,但是都是动态的,new String()所以不是使用同一份。 System.out.println(str5==str6);//false System.out.println(str5.equals(str6));//true String str7 = new String("hello");//有new就是新的 String str8 = new String("hello");//虽然这两个都是在堆的非常量池中动态创建,但是都是动态的,new String()所以不是使用同一份。 System.out.println(str7==str8);//false System.out.println(str7.equals(str8));//true