转载

java字符串赋值比较在写法上的区别

一个简单的字符串比较,以下四种写法有什么区别呢?

写法一:

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 来看一下它们的区别。

写法一:

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 那一段。

写法二:

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 局部变量的操作。

关于方法里的几个命令的作用,见下图:

java字符串赋值比较在写法上的区别

图片来源:《 大话+图说: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 文件。

java字符串赋值比较在写法上的区别

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 局部变量的操作。

原文  https://segmentfault.com/a/1190000021435921
正文到此结束
Loading...