String s1 = "a"; String s2 = "b"; String s3 = "a" + "b"; String s4 = s1 + s2; String s5 = "ab"; String s6 = s4.intern(); // 问 System.out.println(s3 == s4); System.out.println(s3 == s5); System.out.println(s3 == s6); String x2 = new String("c") + new String("d"); String x1 = "cd"; x2.intern(); // 问,如果调换了【最后两行代码】的位置呢,如果是jdk1.6呢 System.out.println(x1 == x2);
// StringTable [ "a", "b" ,"ab" ] hashtable 结构,不能扩容 public class Demo1_22 { // 常量池中的信息,都会被加载到运行时常量池中, 这时 a b ab 都是常量池中的符号,还没有变为 java 字符串对象 // ldc #2 会把 a 符号变为 "a" 字符串对象 // ldc #3 会把 b 符号变为 "b" 字符串对象 // ldc #4 会把 ab 符号变为 "ab" 字符串对象 public static void main(String[] args) { String s1 = "a"; // 懒惰的 String s2 = "b"; String s3 = "ab"; String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString() new String("ab") String s5 = "a" + "b"; // javac 在编译期间的优化,结果已经在编译期确定为ab System.out.println(s3 == s5); } }
反编译class文件后
javap -v Demo1_22.class
Classfile /Users/eistert/Desktop/JVM/JVM/code/jvm/out/production/jvm/cn/itcast/jvm/t1/stringtable/Demo1_22.class Last modified Aug 1, 2021; size 985 bytes MD5 checksum a5eb84bf1a7d8a1e725491f36237777b Compiled from "Demo1_22.java" public class cn.itcast.jvm.t1.stringtable.Demo1_22 minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #12.#36 // java/lang/Object."<init>":()V #2 = String #37 // a #3 = String #38 // b #4 = String #39 // ab #5 = Class #40 // java/lang/StringBuilder #6 = Methodref #5.#36 // java/lang/StringBuilder."<init>":()V #7 = Methodref #5.#41 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #8 = Methodref #5.#42 // java/lang/StringBuilder.toString:()Ljava/lang/String; #9 = Fieldref #43.#44 // java/lang/System.out:Ljava/io/PrintStream; #10 = Methodref #45.#46 // java/io/PrintStream.println:(Z)V #11 = Class #47 // cn/itcast/jvm/t1/stringtable/Demo1_22 #12 = Class #48 // java/lang/Object #13 = Utf8 <init> #14 = Utf8 ()V #15 = Utf8 Code #16 = Utf8 LineNumberTable #17 = Utf8 LocalVariableTable #18 = Utf8 this #19 = Utf8 Lcn/itcast/jvm/t1/stringtable/Demo1_22; #20 = Utf8 main #21 = Utf8 ([Ljava/lang/String;)V #22 = Utf8 args #23 = Utf8 [Ljava/lang/String; #24 = Utf8 s1 #25 = Utf8 Ljava/lang/String; #26 = Utf8 s2 #27 = Utf8 s3 #28 = Utf8 s4 #29 = Utf8 s5 #30 = Utf8 StackMapTable #31 = Class #23 // "[Ljava/lang/String;" #32 = Class #49 // java/lang/String #33 = Class #50 // java/io/PrintStream #34 = Utf8 SourceFile #35 = Utf8 Demo1_22.java #36 = NameAndType #13:#14 // "<init>":()V #37 = Utf8 a #38 = Utf8 b #39 = Utf8 ab #40 = Utf8 java/lang/StringBuilder #41 = NameAndType #51:#52 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #42 = NameAndType #53:#54 // toString:()Ljava/lang/String; #43 = Class #55 // java/lang/System #44 = NameAndType #56:#57 // out:Ljava/io/PrintStream; #45 = Class #50 // java/io/PrintStream #46 = NameAndType #58:#59 // println:(Z)V #47 = Utf8 cn/itcast/jvm/t1/stringtable/Demo1_22 #48 = Utf8 java/lang/Object #49 = Utf8 java/lang/String #50 = Utf8 java/io/PrintStream #51 = Utf8 append #52 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #53 = Utf8 toString #54 = Utf8 ()Ljava/lang/String; #55 = Utf8 java/lang/System #56 = Utf8 out #57 = Utf8 Ljava/io/PrintStream; #58 = Utf8 println #59 = Utf8 (Z)V { public cn.itcast.jvm.t1.stringtable.Demo1_22(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 4: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcn/itcast/jvm/t1/stringtable/Demo1_22; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=6, args_size=1 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: ldc #4 // String ab 8: astore_3 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 16: aload_1 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 20: aload_2 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 27: astore 4 29: ldc #4 // String ab 31: astore 5 33: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 36: aload_3 37: aload 5 39: if_acmpne 46 42: iconst_1 43: goto 47 46: iconst_0 47: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 50: return LineNumberTable: line 11: 0 line 12: 3 line 13: 6 line 14: 9 line 15: 29 line 17: 33 line 21: 50 LocalVariableTable: Start Length Slot Name Signature 0 51 0 args [Ljava/lang/String; 3 48 1 s1 Ljava/lang/String; 6 45 2 s2 Ljava/lang/String; 9 42 3 s3 Ljava/lang/String; 29 22 4 s4 Ljava/lang/String; 33 18 5 s5 Ljava/lang/String; StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 46 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream, int ] } SourceFile: "Demo1_22.java"
String s4 = s1 + s2; 对应的指令
javac 在编译期间的优化,结果已经在编译期确定为ab
/** * 演示字符串字面量也是【延迟】成为对象的 */ public class TestString { public static void main(String[] args) { int x = args.length; System.out.println(); // 字符串个数 2275 System.out.print("1"); System.out.print("2"); System.out.print("3"); System.out.print("4"); System.out.print("5"); System.out.print("6"); System.out.print("7"); System.out.print("8"); System.out.print("9"); System.out.print("0"); System.out.print("1"); // 字符串个数 2285 System.out.print("2"); System.out.print("3"); System.out.print("4"); System.out.print("5"); System.out.print("6"); System.out.print("7"); System.out.print("8"); System.out.print("9"); System.out.print("0"); System.out.print(x); // 字符串个数 2285 } }
1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串 池中的对象返回 1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份, 放入串池, 会把串池中的对象返回
public class Demo1_23 { // ["ab", "a", "b"] public static void main(String[] args) { String x = "ab"; String s = new String("a") + new String("b"); // 堆 new String("a") new String("b") new String("ab") String s2 = s.intern(); // 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回 System.out.println( s2 == x); System.out.println( s == x ); } }