深入字节码学习String常见面试题jdk1.8

题目一:

         String s1 = "a";
        String s2 = "b";
        String s3 = "ab";
        String s4 = s1 + s2;
        System.out.println(s3 == s4);

答案:false

首先贴出反编译后的常量池:


Constant pool:
   #1 = Methodref          #12.#40        // java/lang/Object."<init>":()V
   #2 = String             #41            // a
   #3 = String             #42            // b
   #4 = String             #43            // ab
   #5 = Class              #44            // java/lang/StringBuilder
   #6 = Methodref          #5.#40         // java/lang/StringBuilder."<init>":()V
   #7 = Methodref          #5.#45         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #8 = Methodref          #5.#46         // java/lang/StringBuilder.toString:()Ljava/lang/String;
   #9 = Fieldref           #47.#48        // java/lang/System.out:Ljava/io/PrintStream;
  #10 = Methodref          #49.#50        // java/io/PrintStream.println:(Z)V
  #11 = Class              #51            // DeadLockDemo
  #12 = Class              #52            // java/lang/Object
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               LocalVariableTable
  #18 = Utf8               this
  #19 = Utf8               LDeadLockDemo;
  #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               StackMapTable
  #30 = Class              #23            // "[Ljava/lang/String;"
  #31 = Class              #53            // java/lang/String
  #32 = Class              #54            // java/io/PrintStream
  #33 = Utf8               Exceptions
  #34 = Class              #55            // java/util/concurrent/ExecutionException
  #35 = Class              #56            // java/lang/InterruptedException
  #36 = Utf8               SourceFile
  #37 = Utf8               DeadLockDemo.java
  #38 = Utf8               RuntimeVisibleAnnotations
  #39 = Utf8               Ljdk/nashorn/internal/runtime/logging/Logger;
  #40 = NameAndType        #13:#14        // "<init>":()V
  #41 = Utf8               a
  #42 = Utf8               b
  #43 = Utf8               ab
  #44 = Utf8               java/lang/StringBuilder
  #45 = NameAndType        #57:#58        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #46 = NameAndType        #59:#60        // toString:()Ljava/lang/String;
  #47 = Class              #61            // java/lang/System
  #48 = NameAndType        #62:#63        // out:Ljava/io/PrintStream;
  #49 = Class              #54            // java/io/PrintStream
  #50 = NameAndType        #64:#65        // println:(Z)V
  #51 = Utf8               DeadLockDemo
  #52 = Utf8               java/lang/Object
  #53 = Utf8               java/lang/String
  #54 = Utf8               java/io/PrintStream
  #55 = Utf8               java/util/concurrent/ExecutionException
  #56 = Utf8               java/lang/InterruptedException
  #57 = Utf8               append
  #58 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #59 = Utf8               toString
  #60 = Utf8               ()Ljava/lang/String;
  #61 = Utf8               java/lang/System
  #62 = Utf8               out
  #63 = Utf8               Ljava/io/PrintStream;
  #64 = Utf8               println
  #65 = Utf8               (Z)V

看看具体的汇编代码:

        String s1 = "a";
//        0: ldc           #2                  // String a
//        2: astore_1

        String s2 ="b" ;
//        3: ldc           #3                  // String b
//        5: astore_2

        String s3 = "ab";
//        6: ldc           #4                  // String ab
//        8: astore_3

        String s4 = s1+s2;
//        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

        System.out.println(s3==s4);

从上图来看,当类在编译的时候,会创建出一个常量池,然后执行jvm指令的时候就会根据常量池去查找所需要的东西

当执行下边着几行代码时,都是通过常量池找到这几个常量,然后放入将这几个符号变成字符串对象,最后将字符串对象放入StringTable(串池)中

 但是在执行下面这行代码的时候是完全不同的

 如下图所示

  1. 先执行的是一个new,创建了一个StringBuilder对象
  2. 然后invokespecial    调用了StringBuilder的空参构造方法
  3. 接着aload_1 读取本地变量1的值,也就是a的值
  4. 接着invokevirtual调用了append方法,将a的值作为参数
  5. 继续aload_2读取本地变量2的值,也就是b的值
  6. 然后invokevirtual调用了append方法,将b的值作为参数
  7. 又继续invokevirtual调用了toString的方法,走进源码看Stringbuilder中的toString方法

 又创建了一个String对象,

然后执行astore 将结果放到本地变量4号位值中

至此就完成了

这几行代码的执行

 在最后比较的时候判断s3==s4,由此看来是错误的。s3指向的是StringTable中的字符串对象,而s4指向的是堆中的对象,两个的地址是不相同的,所以false

题目二:

         String s1 = "a";
        String s2 = "b";
        String s3 = "ab";
        String s4 ="a"+"b";
        System.out.println(s3 == s4);

答案:ture

看看具体的汇编代码:

        String s1 = "a";
//        0: ldc           #2                  // String a
//        2: astore_1

        String s2 ="b" ;
//        3: ldc           #3                  // String b
//        5: astore_2

        String s3 = "ab";
//        6: ldc           #4                  // String ab
//        8: astore_3

        String s4 = "a"+"b";
//        9: ldc           #4                  // String ab
//        11: astore        4

不难看出,在执行String s4=“a"+"b";的时候,会先直接找常量池的#4,与执行String s3=”ab“的过程是一样的,因为javac在编译期间就做了优化,”a“+”b“的结果已经是”ab“了

所以结果是ture,都是指向StringTable中的”ab“

猜你喜欢

转载自blog.csdn.net/Promise_J_Z/article/details/121389331