String、StringBuffer与StringBuilder有什么区别?

典型的回答

String是Java语言非常基础和重要类,提供了构造和管理字符串的各种基本逻辑。它是典型的不可变类,被声明成final class,所有属性也都是final的。由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的String对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。

StringBuffer是为了解决上面提到拼接产生太多中间对象的问题而提供的一个类,它是Java 1.5中新增的。StringBuffer本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销。所以除非有线程安全的需要,不然还是推荐使用它的后继者StringBuilder。

StringBuilder在能力上和StringBuffer没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。

知识扩展

1、StringBuffer与StringBuilder实现的一些细节。

StringBuffer与StringBuilder都继承自AbstractStringBuilder,而StringBuffer就是“简单粗暴”地在各种修改数据的方法上加上synchronized关键字。看起来一点都不神秘,有人说“过早优化是万恶之源”,考虑可靠性、正确性和代码可读性才是大多数应用开发最重要的因素。

StringBuffer与StringBuilder的底层都使用了内部数组存储数据。问题是这个内部数组应该开多大呢?目前构建时是在初始字符串长度加16。假设我们需要多次拼接,16这个预留空间很可能会不够,这就会导致不得不多次重新申请空间,再进行arraycopy。显然Java的设计者已经考虑到这个问题,调用者可以通过构造函数的参数指定初始的空间,由此就可以获得更好的性能。

2、StringBuffer与StringBuilder很棒,但是也有一个明显的缺点——不得不敲很多字,可读性也很差。

以下两行代码功能完全相同:

String s1 = new StringBuilder().append("aa").append("bb").append("cc").toString();
String s2 = "aa" + "bb" + "cc";

可以做一个实验,将上面第二行代码先编译再反编译。就会看见,被Java“智能地”翻译为StringBuilder。其实这项特性从Java 6开始就已经提供。所不同的是之后每个Java版本对此项优化都略有改进,不过差别不大。也就是说,大家可以放心的使用上面第二种写法。

3、字符串缓存

有人做过一个粗略的统计,分析程序中对象的组成,发现平均25%的对象是字符串,并且其中约半数是重复的。如果能够避免创建重复字符串,可以有效降低内存消耗和对象创建开销。为此Java从底层就提供了字符串缓存。一般来说,即便程序之中多次出现类似以下代码:

String s = "abc";

其中“abc”无论出现多少次,都只有一个值为“abc”的字符串对象。但是以下代码则会创建一个新的值为“abc”的字符串对象:

String s = new String("abc");

但你仍然可以通过调用intern()方法,将其加入到字符串缓存中。

看起来很不错吧!但实际情况估计会让你大跌眼镜。如果你还在使用Java 6之前的版本,不建议大量使用intern()。原因是缓存的字符串被放在了臭名昭著的“永久代”(PermGen)里,这个空间是有限的。所以如果使用不当,OutOfMemoryError就会光顾。Java 7之后因为缓存的字符串被放到了堆中,这样就极大避免了永久代占满的问题。而Java 8开始永久代被metaSpace(元数据区)替代了。

4、String自身的演化

如果你仔细观察过Java的字符串,在Java 8之前的版本,都是使用char数组来存数据,这样非常直接。但是这是一种浪费,即便是存储英文字母“A”,也需要两个字节。其实在Java 6的时候,Oracle JDK就提供了压缩字符串的特性,但是这个特性的实现不是开源的,而且在实践中也暴露了一些问题,所以在最新的JDK版本中已经将它移除了。

而在Java 9中,引入了Compact Strings,对字符串进行了大刀阔斧的改进。将数据存储方式从char数组改变为一个byte数组加上一个标识编码的所谓coder,并且将相关字符串操作类都进行了修改。即便底层发生了这么大的改变,但是Java字符串的行为却几乎没有变化,所以这个特性对于绝大部分应用来说是透明的,也就是说不要修改已有代码。

是不是没有想到?字符串这么基本的功能,那些语言科学家们做了如此多的努力。真是前人种树后人乘凉!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值