java字節碼-幾種字符串局部變量用法的區別

一個簡單的字符串比較,如下四種寫法有什麼區別呢?java

寫法一:segmentfault

public class TestClass {

    public void test() {
        "str1".equals("str2");
    }

    public static void main(String[] args) {
        new TestClass().test();
    }

}

寫法二:工具

public class TestClass {

    public void test() {
        String str = "str1";
        str.equals("str2");
    }

    public static void main(String[] args) {
        new TestClass().test();
    }

}

寫法三:性能

public class Constans {

    public static final String str1 = "str1";

}

public class TestClass {

    public void test() {
        String str = Constans.str1;
        str.equals("str2");
    }

    public static void main(String[] args) {
        new TestClass().test();
    }

}

寫法四:優化

public class TestClass {

    public void test() {
        String str = "str1";
        String st2 = "str2";
        str.equals(st2);
    }

    public static void main(String[] args) {
        new TestClass().test();
    }

}

以上四種寫法基本上同樣,但若是咱們非要摳一下區別呢,咱們經過javap -c -l TestClass.class來看一下它們的區別。this

寫法一:spa

Compiled from "TestClass.java"
public class com.example.demo.compile.TestClass {
  public com.example.demo.compile.TestClass();
    Code:
       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/example/demo/compile/TestClass;

  public void test();
    Code:
       0: ldc           #2                  // String str1
       2: ldc           #3                  // String str2
       4: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
       7: pop
       8: return
    LineNumberTable:
      line 11: 0
      line 12: 8
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       9     0  this   Lcom/example/demo/compile/TestClass;

  public static void main(java.lang.String[]);
    Code:
       0: new           #5                  // class com/example/demo/compile/TestClass
       3: dup
       4: invokespecial #6                  // Method "<init>":()V
       7: invokevirtual #7                  // Method test:()V
      10: return
    LineNumberTable:
      line 15: 0
      line 16: 10
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  args   [Ljava/lang/String;
}

重點關注 test()下的Code那一段。code

寫法二:blog

Compiled from "TestClass.java"
public class com.example.demo.compile.TestClass {
  public com.example.demo.compile.TestClass();
    Code:
       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/example/demo/compile/TestClass;

  public void test();
    Code:
       0: ldc           #2                  // String str1 將常量「str1」壓入棧
       2: astore_1                          // 將棧中的「str1」pop出,賦值給str
       3: aload_1                           // 將str的引用值壓入棧
       4: ldc           #3                  // String str2
       6: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
       9: pop
      10: return
    LineNumberTable:
      line 11: 0
      line 12: 3
      line 13: 10
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  this   Lcom/example/demo/compile/TestClass;
          3       8     1   str   Ljava/lang/String;

  public static void main(java.lang.String[]);
    Code:
       0: new           #5                  // class com/example/demo/compile/TestClass
       3: dup
       4: invokespecial #6                  // Method "<init>":()V
       7: invokevirtual #7                  // Method test:()V
      10: return
    LineNumberTable:
      line 16: 0
      line 17: 10
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  args   [Ljava/lang/String;
}

能夠看到,在test方法裏,寫法二寫法一多了對str局部變量的操做。
關於方法裏的幾個命令的做用,見下圖:
1622532775-58becf6a14a1b_articlex.png
圖片來源:《大話+圖說:Java字節碼指令——只爲讓你懂圖片

寫法三:

Compiled from "TestClass.java"
public class com.example.demo.compile.TestClass {
  public com.example.demo.compile.TestClass();
    Code:
       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/example/demo/compile/TestClass;

  public void test();
    Code:
       0: ldc           #3                  // String str1
       2: astore_1
       3: aload_1
       4: ldc           #4                  // String str2
       6: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
       9: pop
      10: return
    LineNumberTable:
      line 11: 0
      line 12: 3
      line 13: 10
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  this   Lcom/example/demo/compile/TestClass;
          3       8     1   str   Ljava/lang/String;

  public static void main(java.lang.String[]);
    Code:
       0: new           #6                  // class com/example/demo/compile/TestClass
       3: dup
       4: invokespecial #7                  // Method "<init>":()V
       7: invokevirtual #8                  // Method test:()V
      10: return
    LineNumberTable:
      line 16: 0
      line 17: 10
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  args   [Ljava/lang/String;
}

寫法二寫法三徹底同樣,這是爲何呢?
咱們用反編譯工具打開寫法三class文件。
78664155.png
class文件反編譯後了內容上看,寫法三String str = Constans.str1在編譯後會被轉成String str = "str1",轉以後跟寫法二同樣了。
java在編譯的時候,會作一些性能上的優化,好比:爲了減小運行時的棧調用,將var = 常量字段直接編譯成var = 常量字段的值

寫法四:

Compiled from "TestClass.java"
public class com.example.demo.compile.TestClass {
  public com.example.demo.compile.TestClass();
    Code:
       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/example/demo/compile/TestClass;

  public void test();
    Code:
       0: ldc           #3                  // String str1
       2: astore_1
       3: ldc           #4                  // String str2
       5: astore_2
       6: aload_1
       7: aload_2
       8: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      11: pop
      12: return
    LineNumberTable:
      line 11: 0
      line 12: 3
      line 13: 6
      line 14: 12
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      13     0  this   Lcom/example/demo/compile/TestClass;
          3      10     1   str   Ljava/lang/String;
          6       7     2   st2   Ljava/lang/String;

  public static void main(java.lang.String[]);
    Code:
       0: new           #6                  // class com/example/demo/compile/TestClass
       3: dup
       4: invokespecial #7                  // Method "<init>":()V
       7: invokevirtual #8                  // Method test:()V
      10: return
    LineNumberTable:
      line 17: 0
      line 18: 10
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  args   [Ljava/lang/String;
}

寫法四是在寫法二基礎上,又多了對str2局部變量的操做。

相關文章
相關標籤/搜索