String, StringBuffer 和 StringBuilder之间的区别
String, StringBuffer 和 StringBuilder
可变性
String不可变
StringBuffer 和 StringBuilder 可变
线程安全
String 不可变,因此是线程安全的
StringBuilder不是线程安全的
StringBuffer 是线程安全的,内部使用 synchronized 进行同步
StringBuffer的append方法
@Override
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
拼接字符串建议StringBuilder
源码
String源码,存放字符串的地方
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
StringBuilder自身没有自定义存储的容器,而是继承了其父类的容器
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**The value is used for character storage.*/
char[] value;
...
}
不一样的地方就在于 String 的value是不可变的,而StringBuilder 的value是可变的
String拼接字符串案例
String s1 = "第1个字符串";
String s2 = "第2个字符串";
String str = s1 + s2;
以上操作可以看成是
//这里只作为理解,相当于新开拓一个字符数组,然后复制
final char c1[] = {'第','1','个','字','符','串'};
final char c2[] = {'第','2','个','字','符','串'};
final char c3[] = new char[12];
c3[] = {'第','1','个','字','符','串','第','2','个','字','符','串'};
创建s1的时候其实就是创建了第一个不可变的char[]数组,创建s2的时候创建了第二个不可变的char[]数组
创建str的时候其实就是另外又创建了一个数组,再将s1和s2的数据复制到str中
StringBuilder拼接字符串案例
StringBuilder sb = new StringBuilder();
System.out.println("初始容量:" + sb.capacity());
sb.append("十五个十五个十五个十五个十五个");
System.out.println("追加15个字后sb容量:" + sb.capacity());
sb.append("一");
System.out.println("已经十六个字SB容量:" + sb.capacity());
sb.append("添加");
System.out.println("超过16个字的SB容量:" + sb.capacity());
输出
初始容量:16
追加15个字后sb容量:16
已经十六个字SB容量:16
超过16个字的SB容量:34
StringBuilder特征:StringBuilder初始化容量是16(无参构造)
public StringBuilder() {
super(16);
}
追加之前会计算一次容量,大于所需容量则会重新创建一个char[]数组,计算规则是 newCapacity = (value.length << 1) + 2; 也就是原来长度*2 + 2
StringBuilder在运算的时候每次会计算容量是否足够,如果所需容量不小于自身容量,那么就会重新分配一个自身容量两倍 +2 的char[].
//追加操作
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
//count是当前char[]数组的使用大小,len是要追加的字符串的长度
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//这个方法是确保 char[]数组的大小能装下新追加的字符串
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
//判断所需要的容量是否小于char[]数组的容量
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));//如果小于,就扩容,并拷贝数组内容
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;//扩容数组大小,也就是原来长度*2+2
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
因此,如果再一次追加的时候容量足够,就无需创建新数组,也就省去了很多创建char[]的次数.
小结:
String之所以慢是因为,大部分cpu资源都被浪费在分配资源拷贝资源的部分了,相比StringBuilder有更多的内存消耗。
StringBuilder快就快在,相比String,他在运算的时候分配内存次数小,所以拷贝次数和内存占用也随之减少,当有大量字符串拼接时,StringBuilder创建char[]的次数会少很多。
由于GC的机制,即使原来的char[]没有引用了,那么也得等到GC触发的时候才能回收,String运算过多的时候就会产生大量垃圾,消耗内存。
因此:
如果目标字符串需要大量拼接的操作,那么这个时候应当使用StringBuilder.
反之,如果目标字符串操作次数极少,或者是常量,那么就直接使用String.
String.intern()
调用字符串对象的intern方法,会将该字符串对象尝试放入到串池中
如果串池中没有该字符串对象,则放入成功
如果有该字符串对象,则放入失败
无论放入是否成功,都会返回串池中的字符串对象
注意:此时如果调用intern方法成功,堆内存与串池中的字符串对象是同一个对象;如果失败,则不是同一个对象
例1
//"a" "b" 被放入串池中,str则存在于堆内存之中
String str = new String("a") + new String("b");
//调用str的intern方法,这时串池中没有"ab",则会将该字符串对象放入到串池中,此时堆内存与串池中的"ab"是同一个对象
String st2 = str.intern();
//给str3赋值,因为此时串池中已有"ab",则直接将串池中的内容返回
String str3 = "ab";
//因为堆内存与串池中的"ab"是同一个对象,所以以下两条语句打印的都为true
System.out.println(str == st2);
System.out.println(str == str3);
例2
//此处创建字符串对象"ab",因为串池中还没有"ab",所以将其放入串池中
String str3 = "ab";
//"a" "b" 被放入串池中,str则存在于堆内存之中
String str = new String("a") + new String("b");
//此时因为在创建str3时,"ab"已存在于串池中,所以放入失败,但是会返回串池中的"ab"
String str2 = str.intern();
//false,str在堆内存,str2在串池
System.out.println(str == str2);
//false,str在堆内存,str3在串池
System.out.println(str == str3);
//true,str2和str3是串池中的同一个对象
System.out.println(str2 == str3);
关于作者
来自一线程序员Seven的探索与实践,持续学习迭代中~
本文已收录于我的个人博客:https://www.seven97.top
公众号:seven97,欢迎关注~
String, StringBuffer 和 StringBuilder之间的区别的更多相关文章
- String、StringBuffer、StringBuilder之间的区别
String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) ...
- String、Stringbuffer和Stringbuilder之间的区别
关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺点,到底什么时候该用谁呢?下面我们从以下几点说明一下 1.在执行速度方面:Stringbuilder>Stringbuffer&g ...
- Java中String、StringBuffer和StringBuilder之间的区别
String在Java中是字符串常量 例如 String str = "abc"; str = str + 1; System.out.println(str); 结果将是abc1 ...
- StringBuffer与StringBuilder之间的区别
public class Test { public static void main(String[] args) { StringBuffer strBuffer = new StringBuff ...
- String、StringBuffer与StringBuilder之间区别[全屏看文]
String.StringBuffer与StringBuilder之间区别[全屏看文] 最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,S ...
- String、StringBuffer与StringBuilder之间区别(转)
原文链接:String.StringBuffer与StringBuilder之间区别 最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,Stri ...
- 自己(转)String、StringBuffer与StringBuilder之间区别
String.StringBuffer与StringBuilder之间区别 最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,StringB ...
- String、StringBuffer、StringBuilder他们的区别
String.StringBuffer.StringBuilder他们的区别 String: String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,然后将指针新的对 ...
- String,StringBuffer与StringBuilder
1. String,StringBuffer与StringBuilder的区别 String:存储在常量池中:是不可变的字符序列,任何对String值的改变都会引发新的String对象的生成,因此执行 ...
- StringBuffer与StringBuilder有什么区别
package String比较; /* * StringBuffer与StringBuilder有什么区别 * StringBuilder是JDK5增加的一个新类,功能几乎与StringBuffer ...
随机推荐
- 基于.NET Core + Jquery实现文件断点分片上传
基于.NET Core + Jquery实现文件断点分片上传 前言 该项目是基于.NET Core 和 Jquery实现的文件分片上传,没有经过测试,因为博主没有那么大的文件去测试,目前上传2G左右的 ...
- 高通与At指令:AtCop解析
背景 在某个新基线上移植AT指令,发现有问题,因此收集了这个系列的 文章 作为 这方面的知识补充. 原文作者:laozhuxinlu,本文有删改. 另外,还参考了:https://www.cnblog ...
- python基础-基本语句
1 条件语句 在进行逻辑判断时,我们需要用到条件语句,Python 提供了 if.elif.else 来进行逻辑判断.格式如下所示: 1 if 判断条件1: 2 执行语句1... 3 elif 判断条 ...
- 全志科技T3国产工业评估板规格书(四核ARM Cortex-A7,主频1.2GHz)
1 评估板简介 创龙科技TLT3-EVM是一款基于全志科技T3处理器设计的4核ARM Cortex-A7高性能低功耗国产评估板,每核主频高达1.2GHz,由核心板和评估底板组成. 评估板接口资源丰富, ...
- vba--数组
Sub shishi() Range("e2") = Split(Range("e1"), "-")(0) '用短横线分隔后取第1个值 En ...
- Win10 下安装使用easyocr图片识别工具
[前言] 最近在做图像识别相关的工作,找到了一个名为EasyOCR的pythoh 库. 使用过程中出现了一些问题,现做简单记录. [正文] 1. 安装EasyOCR 我用了最简单的方法:pip3 in ...
- Linux服务器从头配置
安装配置jdk 下载 jdk jdk-8u171-linux-x64.tar.gz 将该压缩包放到/usr/local/jdk目录下然后解压(jdk目录需要自己手动创建) tar zxvf jdk-8 ...
- yb课堂之订单列表接口开发 《十七》
订单列表接口开发 VideoOrderController.java VideoOrderService.java VideoOrderServiceImpl.java VideoOrderMappe ...
- C#——接口
先来看看微软官方对接口的定义与说明. 接口定义协定. 实现接口的类或结构必须遵循它的协定. 接口可以从多个基接口继承,类或结构可以实现多个接口. 接口可以包含方法.属性.事件和索引器. 接口本身不提供 ...
- Tiny RDM 刚上线就收获一众好评的Redis桌面开源客户端!值得拥有!
相信对Redis有频繁操作需求的用户,大部分会选择一个顺手的图形化界面工具来代替手动命令行操作以提高效率.Tiny RDM作为一款现代化轻量级的跨平台Redis桌面客户端,为用户提供了便捷高效的Red ...