String、StringBuffer、StringBuilder 区别

基本概述

String是典型的Immutable类,这个在  final、finally、finalize 区别  中有提到过,类被声明为final、属性被声明为final,由于其不可变的性质,拼接、截取等动作,都会产生新的String对象。

StringBuffer就是为了解决字符串拼接、截取造成的太多中间对象而提供的一个类,它是线程安全的可修改字符序列,但就是由于线程安全机制,导致额外的性能开销,所以该类只适合应用在有线程安全需要的场景。

StringBuilder局部中应用非常多,因为它具备StringBuffer的功能,唯一的不同点,它不是线程安全的。

深入理解

为什么String采用Immutable实现? 因为无法对它内部数据进行任何更改 ,首先 保证了基础线程安全(安全性),其次,不可变使得对象能被共享,不需要额外复制数据(复用性)。

StringBuffer 和 StringBuilder 都 继承了 AbstractStringBuilder ,基本方法都一样,唯一区别是StringBuffer简单粗暴的在方法中加上了synchronized进行修饰,底层利用可修改的char数组

创建时,初始化字符串长度16,如果确定拼接会发生多次并且大概可预测,为了避免多次扩容带来的开销,可以提前设置,扩容是抛弃原来数组、创建新的数组、进行数组拷贝。

优化

   在jdk8中,字符串的拼接操作,会自动被javac转化为StringBuilder操作,在jdk9中,为了更加统一字符串操作优化,提供了StringConcatFactory,作为一个统一的入口。但是jdk7的使用者,需要谨慎选择。

缓存分析

jdk6 提供intern(),提示jvm缓存字符串,创建字符串对象并调用,如果已经缓存过,只会返回缓存实例,但是被缓存的实例是存储在PermGen里,空间有限而且不会被fullgc照顾到,使用不当会导致oom。

在后续版本中,改缓存放置在堆中,避免了永久代占满的问题,默认缓存大小也不断的扩大,从最初1009到7u40以后被修改为60013。

jdk1.7之后,常量池被放到了堆空间中,使得intern()的实现原理也不同。

用例 1:

  String god = new String("hel") + new String("lo");
  System.out.println(god.intern() == god);
  System.out.println(god == "hello");

返回结果 true 、 true

首先,第一行会在常量池存hel 和 lo

 但是,  String god = new String("hel") + new String("lo") 会在堆中生成字符串 hello , 而在常量池中没有

在jdk1.6之前god.intern()会将字符串复制到常量池中,jdk1.7之后,如常量池不存在,则在内存中找,如果内存中有,就在常量池中保存一个指向内存中对象的引用。所以第二段:god.intern() == god  , 返回true

 

用例 2:

String tmp = "hello";
String god = new String("hel") + new String("lo");
System.out.println(god.intern() == god);
System.out.println(god == "hello");

返回 false、false

首先,第一段,已经将hello存放到常量池中

第二段 god 为内存中引用

god.intern() , 因为常量池中存在,所以返回的是常量池中的引用而非内存对象中的引用,所以god.intern() == god 为false

god 是对象引用 , “hello” 是常量池中引用,所以 也为false

 

用例 3:

	String mysq = "aa" + "bb" +  "cc";
	String m = "aabbcc";
	System.out.println(mysq == m);
	System.out.println(m.intern() == mysq);

返回 true 、 true

可见 mysq本身是常量池中引用来

 

用例 4:

String mysq = "aa" + "bb" +  "cc";
String m = new String("aabbcc");
System.out.println(mysq == m);
System.out.println(m.intern() == mysq);

返回 false 、 true

 

题外话

前边提到,字符串存储结构使用char数组进行,但是char是两个bytes大小,导致编程语言的非密度性。jdk9中,字符串底层从char改变为byte数组,期望于更小的内存占用,更快的操作速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值