new String创建了多少个String对象
public class NewString {
public static void main(String[] args) {
String str0 = new String("hello" + " world");
String str1 = "hello" + " world";
String str2 = "hello world";
String str3 = new String("hello") + " wor" + "ld";
String str4 = new String("hello") + new String(" world");
String str5 = "he" + "llo" + new String(" world");
String str6 = (new String("hello") + new String(" world")).intern();
String str7 = "when " + "I " + "was "
+ new String("listen " + " to" + " the") + " radio,"
+ "waiting" + "for ...";
System.out.println(str0 == str1);
System.out.println(str1 == str2);
System.out.println(str2 == str3);
System.out.println(str2 == str4);
System.out.println(str2 == str5);
System.out.println(str2 == str6);
}
}
运行结果:
false
true
false
false
false
true
解析:
可以通过javap解析NewString.class文件。
命令:javap -v c:\NewString.class >>c:\ssu.txt
得到对应常量池信息:
Constant pool:
#1= Class #2 // NewString
#2= Utf8 NewString
#3= Class #4 // java/lang/Object
#4= Utf8 java/lang/Object
#5= Utf8 <init>
#6= Utf8 ()V
#7= Utf8 Code
#8= Methodref #3.#9 // java/lang/Object."<init>":()V
#9= NameAndType #5:#6 // "<init>":()V
#10= Utf8 LineNumberTable
#11= Utf8 LocalVariableTable
#12= Utf8 this
#13= Utf8 LNewString;
#14= Utf8 main
#15= Utf8 ([Ljava/lang/String;)V
#16= Class #17 // java/lang/String
#17= Utf8 java/lang/String
#18= String #19 // hello world
#19= Utf8 hello world
#20= Methodref #16.#21 // java/lang/String."<init>":(Ljava/lang/String;)V
#21= NameAndType #5:#22 // "<init>":(Ljava/lang/String;)V
#22= Utf8 (Ljava/lang/String;)V
#23= Class #24 // java/lang/StringBuilder
#24= Utf8 java/lang/StringBuilder
#25= String #26 // hello
#26= Utf8 hello
#27= Methodref #16.#28 // java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
#28= NameAndType #29:#30 // valueOf:(Ljava/lang/Object;)Ljava/lang/String;
#29= Utf8 valueOf
#30= Utf8 (Ljava/lang/Object;)Ljava/lang/String;
#31= Methodref #23.#21 // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
#32= String #33 // wor
#33= Utf8 wor
#34= Methodref #23.#35 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#35= NameAndType #36:#37 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#36= Utf8 append
#37= Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#38= String #39 // ld
#39= Utf8 ld
#40= Methodref #23.#41 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#41= NameAndType #42:#43 // toString:()Ljava/lang/String;
#42= Utf8 toString
#43= Utf8 ()Ljava/lang/String;
#44= String #45 // world
#45= Utf8 world
#46= Methodref #16.#47 // java/lang/String.intern:()Ljava/lang/String;
#47= NameAndType #48:#43 // intern:()Ljava/lang/String;
#48= Utf8 intern
#49= String #50 // when I was
#50= Utf8 when I was
#51= String #52 // listen to the
#52= Utf8 listen to the
#53= String #54 // radio,
#54= Utf8 radio,
#55= String #56 // waiting
#56= Utf8 waiting
#57= String #58 // for ...
#58= Utf8 for ...
#59= Fieldref #60.#62 // java/lang/System.out:Ljava/io/PrintStream;
#60= Class #61 // java/lang/System
#61= Utf8 java/lang/System
#62= NameAndType #63:#64 // out:Ljava/io/PrintStream;
#63= Utf8 out
#64= Utf8 Ljava/io/PrintStream;
#65= Methodref #66.#68 // java/io/PrintStream.println:(Z)V
#66= Class #67 // java/io/PrintStream
#67= Utf8 java/io/PrintStream
#68= NameAndType #69:#70 // println:(Z)V
#69= Utf8 println
#70= Utf8 (Z)V
#71= Utf8 args
#72= Utf8 [Ljava/lang/String;
#73= Utf8 str0
#74= Utf8 Ljava/lang/String;
#75= Utf8 str1
#76= Utf8 str2
#77= Utf8 str3
#78= Utf8 str4
#79= Utf8 str5
#80= Utf8 str6
#81= Utf8 str7
#82= Utf8 StackMapTable
#83= Class #72 // "[Ljava/lang/String;"
#84= Utf8 SourceFile
#85= Utf8 NewString.java
String str0 = new String("hello"+ " world");
编译器优化后等同于new String("hello world"),
对应常量池中 #19 = Utf8 hello world,
在常量池中找到或者创建“hello world”字符串对象,
在堆中创建“hello world”字符串对象,并将堆中引用返回给str0.
String str1 = "hello" + "world";
编译器优化后等同于"hello world",
对应常量池中 #19 = Utf8 hello world,
在常量池中找到或者创建“hello world”,并且将常量池中引用返回给str1,
在堆中没有创建对象。
String str2 ="hello world" ;
str2和str1一样,返回的是常量池中"hello world"的引用。
String str3 = new String("hello")+ " wor" + "ld";
对应常量池中
#26= Utf8 hello
#33= Utf8 wor
#39= Utf8 ld
在常量池中找到或者创建“hello”,“ wor”和“ld”,
在堆中创建“hello”、“hello world”,并且将堆中引用返回给str3.
字符串的拼接通过StringBuffer完成。
String str4 = new String("hello")+ new String(" world");
对应常量池中
#26= Utf8 hello
#45= Utf8 world
在常量池中找到或者创建“hello”,“ world”,
在堆中创建“hello”,“ world”、“hello world”,并且将堆中引用返回给str4.
String str5 = "he" +"llo" + new String(" world");
编译优化后等同于"hello"+new String(" world");
对应常量池中
#26= Utf8 hello
#45= Utf8 world
在常量池中找到或者创建“hello”,“ world”,
在堆中创建“ world”、“hello world”,并且将堆中引用返回给str5.
String str6 = (newString("hello") + new String(" world")).intern();
对应常量池中
#26= Utf8 hello
#45= Utf8 world
在常量池中找到或者创建“hello”,“ world”,
在堆中创建“hello”、“ world”、“hello world”,
intern作用将在常量池中找到或者创建“helloworld”对象并且返回常量池中引用。
String str7 = "when " + "I" + "was " + new String("listen " + " to" +" the") + " radio," + "waiting" + "for...";
编译器优化后等同于"when I was "+ new String("listen to the") + " radio,"+"waiting" + "for ...";
对应常量池中
#50= Utf8 when I was
#52= Utf8 listen to the
#54= Utf8 radio,
#56= Utf8 waiting
#58= Utf8 for ...
在常量池中创建或者找到“when I was ”、“listen to the”、“ radio,”、“waiting”、“for ...”,
在堆中创建“listen to the”、“when I was listen to the radio,waiting for ...”。
总结:
- 赋值号“=”后面或者new String()里面的连续字符串连接直接优化为连接后的字符串。如"I"+" want"+new String(" tochange"+" the world")等同于"Iwant"+new String(" to change the world"),
- 在new String()后面的连续字符串连接不能被优化。
- 直接字符串则会在常量池中先查找是否有该对象,没有则创建该对象,并且返回常量池中对应引用。
- 有new String()的字符串,则先会在常量池中查找或者创建,让后在堆中创建对象并且返回堆中引用。
- 有new String()的字符串连接,则先会在常量池中查找或者创建,然后在堆中创建对象并且返回堆中引用。
- 有intern()的字符串,最后返回在常量池中查找或者创建的对象。