String类中你不知道的细节

本文介绍了Java中创建字符串的两种方式,指出使用直接量创建对象更高效。还解释了字符串缓冲池,它用于存储JVM运行以来的字符串对象。此外,通过经典面试题探讨了字符串在缓冲池中的情况,最后提到字符串拼接问题及StringBuffer和StringBuilder的使用场景。

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

转自 https://blog.youkuaiyun.com/u010425776/article/details/50760337

跟着大神学事半功倍!大闲人柴毛毛的博客 https://blog.youkuaiyun.com/u010425776

直接量创建对象更高效

在Java中,创建一个字符串有两种方法:


 
 
  1. //第一种方法
  2. String str1 = "字符串1";
  3. //第二种方法
  4. String str2 = new String( "字符串2");
这两种方式创建的字符串在使用上并无区别,但在内存分配方式上完全不同,而且效率大相径庭。下面详细阐述:

第一种方式:

    这种方式创建的字符串对象在堆内存中只需要一块存储空间。系统只需在字符串缓冲池中创建该字符串,并将str1指向该字符串对象。

第二种方式:

    首先创建String类型的对象,再在字符串缓冲池中创建“字符串2”,并将String类型对象指向“字符串2”,再将str2指向String类型对象。

    因此,第一种方式只在堆内存中开辟了一个存储空间,第二种方式在堆内存中开辟了两块存储空间。因此,第一种方式更高效。

    在Java中,所有基本数据类型和String类型都有这两种创建对象的方式,我们把第一种方式称为“使用直接量创建对象”。因此,在Java中,使用直接量创建对象更高效!


字符串缓冲池是什么?

    它存在于堆内存中,用于存储JVM运行以来所有出现过的字符串对象。

    当系统需要创建字符串时,首先判断该字符串是否存在于缓冲池中,若存在则无需创建直接引用,否则创建该字符串。因此,采用直接量方式创建的两个字符串对象是相同的:


 
 
  1. String str1 = "字符串";
  2. String str2 = "字符串";
  3. System.out.println(str1==str2); //结果为true!str1和str2均引用字符串缓冲池中的同一个对象


字符串经典面试题

问:下面程序输出结果是什么?


 
 
  1. String str1 = "我是个大好人6";
  2. String str2 = "我是个"+ "大好人"+ 6;
  3. System.out.println(str1==str2);
输出结果为true!

等号右侧的两个值均在编译时确定下来,因此它们均引用字符串缓冲池中的同一个对象。


问:下面程序输出结果是什么?


 
 
  1. String str1 = "我是个大好人6";
  2. String str2 = "我是个大好人"+ "我是个大好人".length();
  3. int len = 6;
  4. String str3 = "我是个大好人"+len;
  5. System.out.println(str1==str2);
  6. System.out.println(str1==str3);

结果均为false!

由于str2和str3中含有变量或调用了函数,所以str2、str3等号右侧的值在运行阶段才能阶段确定下来,因此它们无法利用字符串缓冲池中的“我是个大好人6”。


问:下面程序输出结果是什么?


 
 
  1. String str1 = "我是个大好人6";
  2. final int len = 6;
  3. String str2 = "我是个大好人"+len;
  4. System.out.println(str1==str2);
结果为true!

此时len被final修饰,len的值固定为6不会发生变化,因此在编译时可以确定str2等号右侧的值为“我是个大好人6”,因此仍然可以沿用字符串池中的“我是个大好人6”。


问:下列程序在字符串缓冲池中创建了几个常量?

String str = "我是个"+"大好人"+6;
 
 
答案为1个!

该字符串中不包含变量和方法,因此在编译时即可确定,编译器看来就是一个完整的常量“我是个大好人6”


问:下列程序在字符串缓冲池中创建了几个常量?


 
 
  1. String str = "我是个";
  2. str = str + "大好人";

 
答案为2个! 

在执行第一行代码时,常量池中创建“我是个”,执行第二行代码时,常量池中再创建“我是个大好人”,并切断str与“我是个”的引用,指向“我是个大好人”,而常量“我是个”继续留在常量池中。

    由于缓冲池中的字符串一般不会被垃圾回收,因此通过这种拼接的方式创建的字符串将会在常量池产生很多碎片,而StringBuffer和StringBuilder就是为了这种问题而诞生的!

    如果一个字符串需要不断发生修改,则使用StringBuffer和StringBuilder比String更加高效。

    StringBuilder是线程安全的,因为在其绝大多数方法都是同步方法,但因此其效率较低;

    综上所述,若程序涉及多线程,应选用StringBuilder;若单线程,则选择StringBuffer效率更高。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值