String常量变量

本文探讨了Java中字符串拼接时的编译时替换现象,详细分析了final修饰符对字符串拼接的影响,并提供了具体的字节码示例。此外,文章还介绍了intern()方法的使用及其效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 类、方法、变量尽量指定fina修饰;
  • 字符串拼接背后不一定是StringBuilder,还可能发生了编译时替换;
  • 用final修饰的字符串在拼接时,在编译的时候会发生编译时替换,直接替换成常量,而不用拼接;

使用final修饰String字节码分析

  • 由于x和y都使用final修饰,在z的赋值中也是直接将常量压栈然后赋值的;
/**
  0: ldc           #8                  // String hello
  2: astore_0
  3: ldc           #46                 // String helloworld
  5: astore_1
  6: ldc           #48                 // String hellohelloworld
  8: astore_2
  9: getstatic     #31                 // Field java/lang/System.out:Ljava/io/PrintStream;
 12: aload_2
 13: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 16: return
* */
public static void f1() {
    final String x="hello";
    final String y=x+"world";
    String z=x+y;
    System.out.println(z);
}

不使用final修饰String字节码分析

  • 由于只有x用final修饰,虽然y的复制还是从常量池压栈赋值,但是z的赋值却new了一个StringBuilder,调用了append()方法;
/**
    0: ldc           #19                 // String hello
    2: astore_1
    3: ldc           #21                 // String helloworld
    5: astore_2
    6: new           #42                 // class java/lang/StringBuilder
    9: dup
   10: ldc           #19                 // String hello
   12: invokespecial #44                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   15: aload_2
   16: invokevirtual #46                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19: invokevirtual #50                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22: astore_3
   23: getstatic     #25                 // Field java/lang/System.out:Ljava/io/PrintStream;
   26: aload_3
   27: invokevirtual #31                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
   30: return
    * */
public void f2(){
        final String x="hello";
        String y=x+"world";
        String z=x+y;
        System.out.println(z);
}

编译时替换示例

  • 因为lo没有用final修饰,所以第4次比较没有发生编译时替换;
  • 关于intern():如果调用的时候,常量池中有这个字符串,就将常量池中的字符串返回;
public class StringLiteral {

    public static class Other {
        public static String hello = "Hello";
    }

    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.println(hello == "Hello");
        System.out.println(Other.hello == hello);
        System.out.println(hello == "Hel"+ "lo");
        System.out.println(hello == ("Hel"+ lo));
        System.out.println(hello == ("Hel"+ lo).intern());
    }

}

输出:

true
true
true
false
true

intern()示例

  • s.intern(); 常量池中已经有了"1",什么也不做,s还是指向堆;
  • s2指向常量池中的"1";
  • s3指向堆中的"11";
  • s3.intern(); 常量池中没有"11",从而常量池中多了一个指向堆中"11"的引用;
  • s4通过常量池指向堆中的"11";
public class AboutIntern {

    public static void main(String[] args) {
        String s = new String("1");
        s.intern();
        String s2 = "1";
        System.out.println(s == s2);
        System.out.println(s.intern() == s2);

        String s3 = new String("1") + new String("1");
        s3.intern();
        String s4 = "11";
        System.out.println(s3 == s4);
    }

}

输出:

false
true
true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值