java stringbuffer原理_深入理解String, StringBuffer, StringBuilder的区别(基于JDK1.8)
String、StringBuffer、StringBuilder都是JAVA中常用的字符串操作类,对于他们的区别大家也都能耳熟能详,但底层到底是怎样实现的呢?今天就再深入分析下这三种字符串操作的区别、各自的原理及使用场景。
请尊重作者劳动成果,转载请标明原文链接:
一、String
先来看一下JDK中String中的部分源码:
public final classStringimplements java.io.Serializable, Comparable, CharSequence {private final charvalue[];private int hash; //Default to 0
publicString() {this.value = new char[0];
}publicString(String original) {this.value =original.value;this.hash =original.hash;
}public String(charvalue[]) {this.value =Arrays.copyOf(value, value.length);
}
...
}
View Code
可以看到String类、以及value都是final类型的,这样就表明String是无法被继承的,value是无法被改写的。当通过String的构造函数初始化新的String对象时,也只是根据传入的引用对象的value和hashcode进行了赋值。看下面的例子:
public classStringTest {public static voidmain(String[] args) {
String str1= "abc";
String str2= "abc";
String Str3= new String("abc");
}
}
Vew Code
执行javac StringTest.java后,通过javap -v StringTest.class看下生成的class文件:
Classfile /C:/Users/jiang/workspace/test/src/test/StringTest.classLast modified2018-7-8; size 363bytes
MD5 checksum f7e4243b0247fb20c5a336d4ba0a580f
Compiled from"StringTest.java"
public classtest.StringTest
minor version:0major version:52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#15 //java/lang/Object."":()V
#2 = String #16 //abc
#3 = Class #17 //java/lang/String
#4 = Methodref #3.#18 //java/lang/String."":(Ljava/lang/String;)V
#5 = Class #19 //test/StringTest
#6 = Class #20 //java/lang/Object
#7 = Utf8 #8 =Utf8 ()V
#9 =Utf8 Code
#10 =Utf8 LineNumberTable
#11 =Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 =Utf8 SourceFile
#14 =Utf8 StringTest.java
#15 = NameAndType #7:#8 //"":()V
#16 =Utf8 abc
#17 = Utf8 java/lang/String
#18 = NameAndType #7:#21 //"":(Ljava/lang/String;)V
#19 = Utf8 test/StringTest
#20 = Utf8 java/lang/Object
#21 = Utf8 (Ljava/lang/String;)V
{publictest.StringTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_01: invokespecial #1 //Method java/lang/Object."":()V
4: returnLineNumberTable:
line3: 0
public static voidmain(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=1
0: ldc #2 //String abc
2: astore_13: ldc #2 //String abc
5: astore_26: new #3 //class java/lang/String
9: dup10: ldc #2 //String abc
12: invokespecial #4 //Method java/lang/String."":(Ljava/lang/String;)V
15: astore_316: returnLineNumberTable:
line6: 0line7: 3line8: 6line9: 16}
SourceFile:"StringTest.java"
View Code
可以看到对于相同的字符串“abc”的引用都是相同的(对于常量池中的相同位置),这样能够节省内存空间,但是缺点就是对于频繁的字符串拼接操作,会造成内存空间的浪费。(需要注意的是这种字符串的拼接操作,从JDK8 开始,会自动被编译成StringBuilder,是不是很666^_^,但还是建议不通过JDK途径去自动转。)看下面的代码:
public classStringTest {public static voidmain(String[] args) {
String str1= "abc";//String str2 = "abc";//String str3 = new String("abc");
String str4 = str1 + "d";
String str5= str4 + "e";
}
}
View Code
然后再通过javap看下class文件:
Classfile /C:/Users/jiang/workspace/test/src/test/StringTest.classLast modified2018-7-8; size 493bytes
MD5 checksum c02bd18ed3ecbe46f9859bf5e272c663
Compiled from"StringTest.java"
public classtest.StringTest
minor version:0major version:52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #10.#19 //java/lang/Object."":()V
#2 = String #20 //abc
#3 = Class #21 //java/lang/StringBuilder
#4 = Methodref #3.#19 //java/lang/StringBuilder."":()V
#5 = Methodref #3.#22 //java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#6 = String #23 //d
#7 = Methodref #3.#24 //java/lang/StringBuilder.toString:()Ljava/lang/String;
#8 = String #25 //e
#9 = Class #26 //test/StringTest
#10 = Class #27 //java/lang/Object
#11 = Utf8 #12 =Utf8 ()V
#13 =Utf8 Code
#14 =Utf8 LineNumberTable
#15 =Utf8 main
#16 = Utf8 ([Ljava/lang/String;)V
#17 =Utf8 SourceFile
#18 =Utf8 StringTest.java
#19 = NameAndType #11:#12 //"":()V
#20 =Utf8 abc
#21 = Utf8 java/lang/StringBuilder
#22 = NameAndType #28:#29 //append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#23 =Utf8 d
#24 = NameAndType #30:#31 //toString:()Ljava/lang/String;
#25 =Utf8 e
#26 = Utf8 test/StringTest
#27 = Utf8 java/lang/Object
#28 =Utf8 append
#29 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#30 =Utf8 toString
#31 = Utf8 ()Ljava/lang/String;
{publictest.StringTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_01: invokespecial #1 //Method java/lang/Object."":()V
4: returnLineNumberTable:
line3: 0
public static voidmain(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: ldc #2 //String abc
2: astore_13: new #3 //class java/lang/StringBuilder
6: dup7: invokespecial #4 //Method java/lang/StringBuilder."":()V
10: aload_111: invokevirtual #5 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 //String d
16: invokevirtual #5 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_223: new #3 //class java/lang/StringBuilder
26: dup27: invokespecial #4 //Method java/lang/StringBuilder."":()V
30: aload_231: invokevirtual #5 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: ldc #8 //String e
36: invokevirtual #5 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: invokevirtual #7 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
42: astore_343: returnLineNumberTable:
line6: 0line9: 3line10: 23line11: 43}
SourceFile:"StringTest.java"
View Code
二、StringBuilder
也是先来看StringBuilder的源码:
public final classStringBuilderextendsAbstractStringBuilderimplementsjava.io.Serializable, CharSequence
{publicStringBuilder() {super(16);
}publicStringBuilder(String str) {super(str.length() + 16);
append(str);
}publicStringBuilder append(String str) {super.append(str);return this;
}
...
}abstract class AbstractStringBuilder implementsAppendable, CharSequence {char[] value;intcount;
AbstractStringBuilder(intcapacity) {
value= new char[capacity];
}publicAbstractStringBuilder append(String str) {if (str == null)returnappendNull();int len =str.length();
ensureCapacityInternal(count+len);
str.getChars(0, len, value, count);
count+=len;return this;
}
...
}
View Code
可以看到StringBuilder的value是个char数组,(当然从JDK9开始,value从char数组变成了byte数组)。每次append时都是通过调用native的System.arraycopy实现的(在getChars中调用的)。
三、StringBuffer
S tringBuffer的源码如下:
public final classStringBufferextendsAbstractStringBuilderimplementsjava.io.Serializable, CharSequence
{private transient char[] toStringCache;publicStringBuffer() {super(16);
}publicStringBuffer(String str) {super(str.length() + 16);
append(str);
}public synchronizedStringBuffer append(String str) {
toStringCache= null;super.append(str);return this;
}
...
}
View Code
和StringBuilder一样,都是用了char数组保存value,append也是调用了AbstractStringBuilder的append方法。区别只是在于char数组加了transient关键字,以及方法上加了synchronized方法。
综上所述,String、StringBuilder、StringBuffer的使用场景如下:
当处理定长字符串时,建议用String;
当处理变长字符串时,并且是单线程环境时,建议用StringBuilder;
当处理变长字符串时,并且是多线程环境时,建议用StringBuffer。
java stringbuffer原理_深入理解String, StringBuffer, StringBuilder的区别(基于JDK1.8)相关推荐
- java stringbuffer原理_深入理解Java:String
在讲解String之前,我们先了解一下Java的内存结构. 一.Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配. JVM主要管理两 ...
- c#中的string和StringBuilder的区别
string和StringBuilder的区别 解析c#中的string和StringBuilder的区别,只有非常了解后我们才能更好的编程和灵活使用. 区别 1.类 String 表示字符串, 比如 ...
- string 与stringbuilder的区别
string 与stringbuilder的区别 C# String 对象是不可改变的.每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就 ...
- java 常量折叠_深入理解Java虚拟机之早期编译器优化
Javac编译器 Javac编译器是一个由Java语言编写的程序 Javac的源码与调试 从Sun Javac的代码来看,编译器大致分为3个过程: 解析与填充符号表的过程 插入式注解处理器的注解处理过 ...
- String和StringBuilder的区别
1 String和StringBuilder拼接字符串的区别 总的来说吧,String类的内容是不可变的,StringBuilder的内容是可变的 有好长一段时间都很迷这个String和StringB ...
- String 和stringBuilder的区别
string和stringbuilder对象都可以很方便的处理字符串: string是引用类型,在堆上分配内存.string对象一旦创建变不能再改变.在用算时会产生一个新的实例. Stringbuil ...
- java装箱与拆箱原理_深入理解Java中的装箱和拆箱
前言 自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题.本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱.拆箱相关的问题. 若有不 ...
- 微博java实现原理_【转】URL短地址压缩算法 微博短地址原理解析 (Java实现)...
最近,项目中需要用到短网址(ShortUrl)的算法,于是在网上搜索一番,发现有C#的算法,有.Net的算法,有PHP的算法,就是没有找到Java版的短网址(ShortUrl)的算法,很是郁闷.同时还 ...
- java foreach 原理_一不小心就让Java开发者踩坑的failfast是个什么鬼?
1 什么是fail-fast 首先我们看下维基百科中关于fail-fast的解释: 在系统设计中,快速失效系统一种可以立即报告任何可能表明故障的情况的系统.快速失效系统通常设计用于停止正常操作,而不是 ...
最新文章
- 2022-2028年中国喷涂速凝橡胶行业市场调研分析及未来前景分析报告
- 单目视觉里程计性能估计
- scala函数式编程(二) scala基础语法介绍
- 161026、更快速将你的页面展示给用户[前端优化篇]
- MySQL Percona Toolkit--pt-osc与online DDL选择
- 两组声音的一维数据如何比较相似度_TSNE高维数据降维可视化工具 入门到理解 + python实现...
- SDWebImage缓存图片的机制(转)
- 中国手机摄像头产业链
- DPDK Release 22.07
- python股票成交明细_AkShare-股票数据-龙虎榜-机构席位成交明细
- 如何修改linux启动项目路径,Jetty配置虚拟目录,实现把web项目发布到自定义目录,指定指定上下文访问;jetty编码修改;Jetty加入Linux service实现开机自启动...
- 北理大编程作业:确定母亲节
- Mixed Precision Training混合精度训练笔记及框架代码
- js中浏览器失焦获焦的几种结局方法
- Alpha版本——展示博客【第二组】
- jquery中的各种动画效果
- css背景图铺满整个屏幕
- 2019年个人总结,写在人生不惑之年
- 契约锁android代码,契约锁怎么签合同
- 外语学习的真实方法与误区19
热门文章
- mysql 出现 quot_mysql 出现 quot;the table is fullquot;的问题 - tmuffamd - ITeye博客
- 玩转SpringBoot2.x之缓存对象
- Win10 通过 VirtualBox安装CentOS7操作手册
- win8安装mysql出现2503_win8.1安装msi文件出现2503错误的解决方法
- 基于JAVA+SpringMVC+MYSQL的求职招聘管理系统
- linux内核模块签名,linux内核模块签名
- my stackoverflow
- Asp.net Mvc使用PagedList分页
- Linux 添加环境变量
- 分形之希尔伯特-皮亚诺(Hilbert-Peano)曲线