Java 6 和 Java 8中String、StringBuffer与StringBuilder的区别

一、String

String的创建机制

因为String在Java中使用过于频繁,Java为了避免在系统中产生大量的String对象,引入了字符串常量池的概念。

其运行机制是:

创建一个字符串时,首先检查池中是否有值相同的字符串对象(equals决定),如果有则不需要创建而是直接从常量池中找到的该字符串对象的引用;
如果没有则新建一个字符串对象,返回该对象引用,并且将新创建的字符串对象放入池中

但是通过new方法创建的String对象是不检查字符串池的,而是直接在堆区或栈区创建一个新的对象,也不会把对象放入池中。

//通过直接量赋值方式,放入字符串常量池
String str1 = "123"; 
//通过new方式赋值方式,不放入字符串常量池
String str2 = new String(“123”);
str1 == str2 // false
String str3 = "1" + "2" + "3";
str3 == str1 // true
//在编译期的时候,str3即被编译成"123"字符串,而此时常量池中已经存在该字符串,所以str3与str1是相等的
String的特性

不可变
String对象一旦生成,则不能再对它的值进行改变,这里的不可变指这个字符串对象无法改变,而我们平时定义的字符串变量虽然可以改变,但是实质上它是改变了这个变量的引用,相当于将这个变量指向了另外一个字符串对象,而一开始的字符串对象还是没有变的。
不可变的主要作用在于当一个对象需要被多线程共享,并且访问频繁时,可以省略同步和锁等待的时间,从而大幅度提高系统性能。

为什么不可变
我们看String的源码可以发现String底层是采用字符数组(char[])来存储字符串值,该数组的定义如下

private final char value[];

这个数组定义为private final,在java中数组也是对象,所以当String对象一旦初始化完成,其内部变量value的引用就无法改变,顶多只能改变数组中元素的值,但是在看遍String的所有方法后,发现String中根本没有一个方法可以改变value这个char数组里面的元素,所以在String初始化完成后即不可变。

虽然我们在编码过程中经常会调用StringtoLowerCase,substring等方法,但是实际上这是生成的一个新字符串对象,只是将变量的引用指向了这个新对象,而没有改变原有字符串对象的值。

StringBuffer 和 StringBuilder

StringBufferStringBuilder都实现了AbstractStringBuilder抽象类,拥有几乎一致对外提供的调用接口;
其底层在内存中的存储方式与String相同,都是采用char数组存储数据,只是这个char数组没被final修饰,因此这个char数组的引用可以改变且该数组中的元素也可以改变,所以StringBuffer/StringBuilder对象的值是可以改变的。

StringBuffer/StringBuilder在改变char数组过程中是在该对象自身内部进行的,所以对象本身的引用还是同一个。因此定义一个StringBuffer/StringBuilder变量,修改其值之后,其引用还是同一个,不会改变。

两者对象在构造过程中,首先按照默认大小申请一个字符数组,由于会不断加入新数据,当超过默认大小后,会创建一个更大的数组,并将原先的数组内容复制过来,再丢弃旧的数组。因此,对于较大对象的扩容会涉及大量的内存复制操作,如果能够预先评估大小,可提升性能。

唯一需要注意的是:StringBuffer是线程安全的,但是StringBuilder是线程不安全的。可参看Java标准类库的源代码,StringBuffer类中方法定义前面都会有synchronized关键字。为此,StringBuffer的性能要远低于StringBuilder

应用场景

在字符串内容不经常发生变化的业务场景优先使用String类。例如:常量声明、少量的字符串拼接操作等。如果有大量的字符串内容拼接,避免使用StringString之间的" + "操作,因为这样会产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。

在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程环境下,建议使用StringBuffer,例如XML解析、HTTP参数解析与封装。

在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在单线程环境下,建议使用StringBuilder,例如SQL语句拼装、JSON封装等。

以上是java 6以前的版本,而Java 8默认使用StringBuilder拼接字符串,所以不用显示的使用StringBuilder了,直接用“+”就可以了。

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

推荐阅读更多精彩内容