Java基础之 解开String 的神密面纱

Posted hongshu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础之 解开String 的神密面纱相关的知识,希望对你有一定的参考价值。

先来一个引子,来打开这个话题吧

public static void main(String[] args) 

        String s1 = "hello world";
        String s2 = new String("hello world");
        String s3 = new String("hello world").intern();
        String s4 = new String("hello world");
        String s5 = "hello world";


        System.out.println(s1==s5);
        System.out.println(s1==s2);
        System.out.println(s1==s3);
        
        
        System.out.println(s2==s4);
        System.out.println(s2==s3);


    

如果你能毫不犹豫的说上面代码运行的结果,说明你对String有一定的了解了。你也能通过String相关问题的面试了,但你能说出为什么,你对 ==的机制就更了解。哈哈,不多费话了,直接上运行的结果吧,以此来打开我讨论的话题。

Disconnected from the target VM, address: '127.0.0.1:50688', transport: 'socket'
true
false
true
false
false

先来解释下原因,

  • s1==s5,是因为s1,s5的指针都指向了常量池中 hello world.
  • s1==s2 为false,虽然在编译期间,字面量s1,s2都指向了常量池中的hello world,但在运行期间,但s2在运行期间又被new String load成了一个对象,该对象批向了常量池中 hello world的地址,所以会为false
  • s1==s3 按上面所说,这个应该是false,但又为什么会是true呢?我们可以看下inner()方法的实现
    public native String intern();加了native进行修饰,说明是native变量,说明该方法会常量池中是的引用,所以是true
  • s2==s4,s2==s4比较容易理解,是两个不同对象的,==肯定为false

为了更好的理解上面说的问题,让我们来看class的内容,javap以的内容如下

/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home\\bin\\javap -c -l -s -verbose com.hongshu.gold.biz.base.TestString
Classfile /Users/hongshu/work/IdeaProjects/oschina/gold-trade/biz/target/classes/com/hongshu/gold/biz/base/TestString.class
  Last modified Sep 7, 2018; size 1135 bytes
  MD5 checksum a75719013829a0e0ed0efe8695d5751f
  Compiled from "TestString.java"
public class com.hongshu.gold.biz.base.TestString
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #9.#33         // java/lang/Object."<init>":()V
   #2 = String             #34            // hello world
   #3 = Class              #35            // java/lang/String
   #4 = Methodref          #3.#36         // java/lang/String."<init>":(Ljava/lang/String;)V
   #5 = Methodref          #3.#37         // java/lang/String.intern:()Ljava/lang/String;
   #6 = Fieldref           #38.#39        // java/lang/System.out:Ljava/io/PrintStream;
   #7 = Methodref          #40.#41        // java/io/PrintStream.println:(Z)V
   #8 = Class              #42            // com/hongshu/gold/biz/base/TestString
   #9 = Class              #43            // java/lang/Object
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Lcom/hongshu/gold/biz/base/TestString;
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               args
  #20 = Utf8               [Ljava/lang/String;
  #21 = Utf8               s1
  #22 = Utf8               Ljava/lang/String;
  #23 = Utf8               s2
  #24 = Utf8               s3
  #25 = Utf8               s4
  #26 = Utf8               s5
  #27 = Utf8               StackMapTable
  #28 = Class              #20            // "[Ljava/lang/String;"
  #29 = Class              #35            // java/lang/String
  #30 = Class              #44            // java/io/PrintStream
  #31 = Utf8               SourceFile
  #32 = Utf8               TestString.java
  #33 = NameAndType        #10:#11        // "<init>":()V
  #34 = Utf8               hello world
  #35 = Utf8               java/lang/String
  #36 = NameAndType        #10:#45        // "<init>":(Ljava/lang/String;)V
  #37 = NameAndType        #46:#47        // intern:()Ljava/lang/String;
  #38 = Class              #48            // java/lang/System
  #39 = NameAndType        #49:#50        // out:Ljava/io/PrintStream;
  #40 = Class              #44            // java/io/PrintStream
  #41 = NameAndType        #51:#52        // println:(Z)V
  #42 = Utf8               com/hongshu/gold/biz/base/TestString
  #43 = Utf8               java/lang/Object
  #44 = Utf8               java/io/PrintStream
  #45 = Utf8               (Ljava/lang/String;)V
  #46 = Utf8               intern
  #47 = Utf8               ()Ljava/lang/String;
  #48 = Utf8               java/lang/System
  #49 = Utf8               out
  #50 = Utf8               Ljava/io/PrintStream;
  #51 = Utf8               println
  #52 = Utf8               (Z)V

  public com.hongshu.gold.biz.base.TestString();
    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 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/hongshu/gold/biz/base/TestString;

  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 hello world
         2: astore_1
         3: new           #3                  // class java/lang/String
         6: dup
         7: ldc           #2                  // String hello world
         9: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
        12: astore_2
        13: new           #3                  // class java/lang/String
        16: dup
        17: ldc           #2                  // String hello world
        19: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
        22: invokevirtual #5                  // Method java/lang/String.intern:()Ljava/lang/String;
        25: astore_3
        26: new           #3                  // class java/lang/String
        29: dup
        30: ldc           #2                  // String hello world
        32: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
        35: astore        4
        37: ldc           #2                  // String hello world
        39: astore        5
        41: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
        44: aload_1
        45: aload         5
        47: if_acmpne     54
        50: iconst_1
        51: goto          55
        54: iconst_0
        55: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
        58: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
        61: aload_1
        62: aload_2
        63: if_acmpne     70
        66: iconst_1
        67: goto          71
        70: iconst_0
        71: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
        74: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
        77: aload_1
        78: aload_3
        79: if_acmpne     86
        82: iconst_1
        83: goto          87
        86: iconst_0
        87: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
        90: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
        93: aload_2
        94: aload         4
        96: if_acmpne     103
        99: iconst_1
       100: goto          104
       103: iconst_0
       104: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
       107: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
       110: aload_2
       111: aload_3
       112: if_acmpne     119
       115: iconst_1
       116: goto          120
       119: iconst_0
       120: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
       123: return
      LineNumberTable:
        line 13: 0
        line 14: 3
        line 15: 13
        line 16: 26
        line 17: 37
        line 20: 41
        line 21: 58
        line 22: 74
        line 25: 90
        line 26: 107
        line 29: 123
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0     124     0  args   [Ljava/lang/String;
            3     121     1    s1   Ljava/lang/String;
           13     111     2    s2   Ljava/lang/String;
           26      98     3    s3   Ljava/lang/String;
           37      87     4    s4   Ljava/lang/String;
           41      83     5    s5   Ljava/lang/String;
      StackMapTable: number_of_entries = 10
        frame_type = 255 /* full_frame */
          offset_delta = 54
          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 ]
        frame_type = 78 /* same_locals_1_stack_item */
          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 ]
        frame_type = 78 /* same_locals_1_stack_item */
          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 ]
        frame_type = 79 /* same_locals_1_stack_item */
          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 ]
        frame_type = 78 /* same_locals_1_stack_item */
          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: "TestString.java"

Process finished with exit code 0

常量池中字面量引用只有一个 helloworld的引用 这说明,虽然声明多个变量,String为了提高其性,在编译时,只在常量池中生一个引用。

 

未完待续

以上是关于Java基础之 解开String 的神密面纱的主要内容,如果未能解决你的问题,请参考以下文章

解开Future的神秘面纱之取消任务

解开Future的神秘面纱之任务执行

解开Future的神秘面纱之获取结果

解开MongoDB神秘的面纱

解开Redis的神秘面纱

解开XAML的邪恶面纱