字符串常量池,String字面量创建和new创建的区别,intern(),字符串拼接

本文详细介绍了Java中String对象的两种创建方式——字面量和new操作符,以及intern()方法的作用和字符串拼接的原理。讲解了字面量创建时String Pool的工作机制,new操作符如何影响内存分配,以及如何利用intern()方法优化内存使用。同时,通过实例展示了字符串拼接可能导致的额外对象创建问题,并给出了最佳实践建议。
摘要由CSDN通过智能技术生成

1 String 对象的两种创建方式

1.1 字面量

String str1 = "abcd";

字面量方式会创建0或1个对象:

  1. 如果String Pool 中没有 “abcd” 字符串对象,编译期会在String Pool中创建一个“abcd”字符串对象,运行期返回String Pool 中该“abcd”字符串对象的引用;
  2. 如果String Pool 中已经有一个 “abcd” 字符串对象,则编译期不创建新的"abcd" 字符串对象,运行期直接返回String Pool 中该 “abcd” 字符串对象的引用;
String s1 = "abcd";
String s2 = "abcd";
System.out.println(s1 == s2);  // true

1.2 new

String str2 = new String("abcd");

new方式会创建1或2个字符串对象:

  1. 如果String Pool 中没有 “abcd” 字符串对象,编译期会在String Pool中创建一个"abcd"字符串对象;如果String Pool 中已经有一个 “abcd” 字符串对象,则编译期不创建新的"abcd" 字符串对象;
  2. 运行期使用 new 的方式在堆中创建另外一个"abcd"字符串对象 ,并返回该字符串对象的引用;
String s1 = new String("abcd");
String s2 = new String("abcd");
System.out.println(s1 == s2);  // false

2 intern() 方法

  1. 字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定;
  2. 不仅如此,还可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中;
  3. 当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定), 那么就会返回 String Pool 中字符串的引用; 否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用;
String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);           // false
String s3 = s1.intern();
String s4 = s1.intern();
System.out.println(s3 == s4);           // true

在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。 而在 Java 8以后,String Pool被移到堆中,这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

3 字符串拼接

String str1 = "str";
String str2 = "ing";
		  
String str3 = "str" + "ing";//常量池中的对象
String str4 = str1 + str2; //TODO:在堆上创建的新的对象	  
String str5 = "string";//常量池中的对象
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false

在这里插入图片描述

注意:尽量避免多个字符串拼接,因为这样会重新创建对象。 如果需要改变字符串的话,可以使用 StringBuilder 或者 StringBuffer。

public class Test {
    public static void main(String[] args) {
        //(1)
        String a = "ab";   
        String bb = "b";   
        String b = "a" + bb;   
        System.out.println((a == b)); // false 

        //(2)
        String a1 = "ab";   
        final String bb1 = "b";   
        String b1 = "a" + bb1;   
        System.out.println((a1 == b1)); // true 

        //(3)
        String a2 = "ab";   
        final String bb2 = getBB();   
        String b2 = "a" + bb2;   
        System.out.println((a2 == b2)); // false        
    }
    
    private static String getBB(){
        return "b";   
    }
    
}
  1. JVM对于字符串引用,由于在字符串的”+”连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即”a” + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。
  2. (2)和(1)中唯一不同的是bb1字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的”a” + bb1和”a” + “b”效果是一样的。故上面程序的结果为true。
  3. JVM对于字符串引用bb2,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和”a”来动态连接并分配地址为b2,故上面程序的结果为false。
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hellosc01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值