五、String、StringBuffer、StringBuilder有什么区别

一、概念
1、String是Java语言中非常重要和基础的类,所有在Java程序中的字符串字面量,比如

"abc"

,String类是一个典型的不可变类,被声明成为final class,所有属性也是final的,创建出来之后不能再修改,所以类似下面这两端代码是等价的,都会创建"abc"字符串:

String str = "abc";
char data[] = {'a', 'b', 'c'};
String str = new String(data);

String构造函数不能传入null值,否则会报空指针的错误:

String nullStr = null;
String s5 = new String(nullStr);

同时由于它的不可变性,类似拼接、裁剪字符串等动作都会产生新的String对象。
由于字符串操作的普遍性,所以相关操作的效率往往对应用性能会有影响。

2、StringBuffer是一个线程安全的、支持可变字符的序列。StringBuffer与String非常像,但是它的字符序列是可修改的,可以解决String拼接产生太多中间对象的问题而提供的一个类,我们可以使用append或者add方法,把字符串添加到已有序列的末尾或者指定位置,它保证了线程安全,但是也随之带来了额外的性能开销,因为StringBuffer的线程安全是通过synchronized关键字来保证的,所以除非有线程安全的需要,不然还是尽量使用它的后继者,也就是StringBuilder。每一个StringBuffer有一个容量,字符序列的长度不能超过这个容量。不能准确预估容量时一般不要来指定长度,因为StringBuffer会自动进行扩容,默认的初始容量为16:

/**
 * Constructs a string buffer with no characters in it and an
 * initial capacity of 16 characters.
 */
public StringBuffer() {
    super(16);
}

。如果确定程序会进行很多次拼接,而且大概是可预估的,那么就可以指定合适的大小,避免多次扩容的开销。扩容会产生多重开销,因为要抛弃原有的数组,创建新的数组,还要进行arrayCopy。

3、StringBuilder是在JDK1.5中新增的,在能力上与StringBuffer并没有本质的区别,可以看到他们都是继承了java.lang.AbstractStringBuilder这个类,但是它去掉了线程安全的部分,有效减小了开销,在绝大部分情况下是字符串拼接的首选。

二、字符串缓存
我们粗略统计过,把常见的应用进行堆转储(Dump Heap),然后分析对象组成,会发现平均25%的对象时字符串,并且其中约半数是重复的。如果能避免创建重复字符串,可以有效降低消耗和对象创建开销。
String在JDK1.6之后提供了intern()方法,目的是提示JVM把相应字符串缓存起来,以备重复使用。我们咋调用intern方法的时候,如果字符串常量池里已经有缓存的字符串就会返回缓存里的实例,否则将其缓存起来并返回,判断是否相等使用equals()方法判断,当且仅当

s.equals(t)==true
s.intern() == t.intern()==true

并且所有所有文本字符串和字符串值常量表达式都是会被缓存的。一般使用Java6这种历史版本,并不推荐大量使用intern,因为被缓存的字符串是保存在PermGen(永久代),这个空间是有限的,也基本不会被FullGC之外的垃圾收集光顾到,一旦使用不当就会发生OOM。在JDK后续版本中,这个缓存被放置在堆中,这样就极大避免了永久代被占满的问题,甚至永久代在JDK8中被MetaSpace(元数据区)替代了。而且默认缓存区大小也在不断的扩大中,从最初的1009到7u40以后被修改为60013。可以使用下面的参数直接打印具体数字:

-XX:+PrintStringTableStatistics

也可以使用下面的JVM参数手动调整大小,但是绝大部分情况下并不需要调整,除非能够确定它的大小已经影响到了操作效率。

-XX:StringTableSize=N

intern是一种显式的排重机制,但是它也有一定的副作用,因为需要开发者写代码的时候手动调用,一是不方便,每一个显式调用是非常麻烦的,另外就是很难来保证效率,应用开发阶段很难预估到字符串的重复情况,也有人认为这是一种污染代码的实践。幸好在Oracle JDK 8u20之后,推出了一个新的特性,也就是G1 GC下的字符串排重。它是通过将相同数据的字符串指向同一份数据来做到的,是JVM底层的改变,并不需要Java类库做修改。这个功能目前默认是关闭的,需要使用下面的参数开启,并且需要指定使用G1 GC:

-XX:+UseStringDeduplication

三、String自身的演化
Java的字符串在历史版本中是使用char数组来存放数据的,这样非常直接。但是Java中的char是两个byte大小,拉丁语系语言的字符不需要太宽的char,这样无区别的实现造成了一定的资源浪费。密度是编程语言平台永恒的话题,因为归根结底绝大部分任务是用来操作数据的。

在JDK 9中引入了Compact strings的设计,对字符串进行了大刀阔斧的改进。将数据存储方式从char数组改变为一个byte数组加上一个标识编码的所谓coder,并且将相关字符串操作类进行了修改。虽然底层发生了这么大的改变,但是Java字符串的行为并没有任何大的变化,这个特性对于绝大部分应用来说都是透明的,绝大部分情况下不需要修改已有的代码。可能在极端情况下字符串能的能力也出现了一些能力退化,比如最大字符串的大小。原来char数组的实现,字符串的最大长度就是数组本身的长度限制,但是替换成了byte数组,同样数组长度下,存储能力是退化了一倍的。在通用的性能测试和产品实验中,我们能非常明显的看到紧凑字符串带来的优势,即更小的内存占用、更快的操作速度。

四、getBytes和String相关的转换时最好根据业务需要建议指定编码方式,如果不指定则看JVM参数里有没有指定file.encoding参数,如果JVM没有指定,那使用的默认编码就是运行的操作系统环境的编码了,那这个编码就变得不确定了。常见的编码ISO8859-1是单字节编码,UTF-8是变长的编码。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容