Java基础 StringBuffer、StringBuilder原理浅析
StringBuilder与StringBuffer作用就是用来处理字符串,但String类本身也具备很多方法可以用来处理字符串,那么为什么还要引入这两个类呢?
首先看下面的例子
public static void main(String[] args) {
String str0 = "hel,lo,wor,l,d";
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++){
str0 += i;
}
System.out.println(System.currentTimeMillis() - start);
StringBuilder sb = new StringBuilder("hel,lo,wor,l,d");
long start1 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++){
sb.append(i);
}
System.out.println(System.currentTimeMillis() - start1);
StringBuffer sbf = new StringBuffer("hel,lo,wor,l,d");
long start2 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++){
sbf.append(i);
}
System.out.println(System.currentTimeMillis() - start2);
}
上述代码中3处循环完成了同样的功能,字符串拼接,执行的结果如下:
36823
3
4
可以看出执行时间差别太大,为了解决String不擅长的大量字符串拼接这种业务场景,引入了StringBuffer和StringBuilder.
首先我们分析一下为什么String在大量字符串拼接这种场景下这么慢?
因为String本身不可变,我们对String的任何操作都会返回一个新的对象,然后当前String变量指向新的对象,而原来的String对象就会被GC回收,那么在循环中就会大量快速的创建新的对象,大量原来的对象会不断的被GC回收,消耗的时间是非常恐怖的,而且内存占用非常大。
下面我们对比了String、StringBuffer与StringBuilder的区别
String StringBuffer StringBuilder
final修饰,不可继承 final修饰,不可继承 final修饰,不可继承
字符串常量,创建后不可变 字符串变量,可动态修改 字符串变量,可动态修改
不存在线程安全问题 线程安全,所有public方法由synchronized修改 线程不安全
大量字符串拼接效率最低 大量字符串拼接效率非常高 大量字符串拼接效率最高
StringBuffer与StringBuilder实现非常类似,下面以StringBuilder简单说明一下append()方法基本原理
1. 首先创建一个StringBuilder
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder(100);
StringBuilder对字符串的操作是通过char[]来实现的,通过默认构造器创建的StringBuilder,其内部创建的char[]的默认长度为16,当然可以调用重载的构造器传递初始长度(推荐这样,因为这样可以减少数组扩容次数,提高效率)。
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
2. StringBuilder的append()方法
每次调用append(str)方法时,会首先判断数组长度是否足以添加传递来的字符串
/**
* Appends the specified string to this character sequence.
*
* The characters of the {@code String} argument are appended, in
* order, increasing the length of this sequence by the length of the
* argument. If {@code str} is {@code null}, then the four
* characters {@code "null"} are appended.
*
* @param str a string.
* @return a reference to this object.
*/
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
/**
* For positive values of {@code minimumCapacity}, this method
* behaves like {@code ensureCapacity}, however it is never
* synchronized.
* If {@code minimumCapacity} is non positive due to numeric
* overflow, this method throws {@code OutOfMemoryError}.
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}无锡渤海医院做人流 http://www.89906662.com/
如果传递的字符串长度 + 数组已存放的字符的长度 > 数组的长度,这时就需要进行数据扩容了
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by the same amount + 2 if
* that suffices.
* Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
* unless the given minimum capacity is greater than that.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero or
* greater than Integer.MAX_VALUE
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
扩容规则如下:默认将数组长度设置为“ (当前数组长度 * 2) + 2”,但如果按此规则扩容后的数组也不足以添加新的字符串,就需要将数组长度设置为“数组内字符长度 + 传递的字符串长度”。
因此假如我们知道拼接的字符串大概长度有100多字符,我们就可以设置初始长度150或200,这样就可以避免或减少数组扩容的次数,从而提高效率。
Java基础 StringBuffer、StringBuilder原理浅析的更多相关文章
- Java基础-StringBuffer类与StringBuilder类简介
Java基础-StringBuffer类与StringBuilder类简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.StringBuffer类 在学习过String类之后 ...
- Java基础(四) StringBuffer、StringBuilder原理浅析
StringBuilder与StringBuffer作用就是用来处理字符串,但String类本身也具备很多方法可以用来处理字符串,那么为什么还要引入这两个类呢? 关于String的讲解请看Java基础 ...
- Java基础(五) final关键字浅析
前面在讲解String时提到了final关键字,本文将对final关键字进行解析. static和final是两个我们必须掌握的关键字.不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提 ...
- Java String StringBuffer StringBuilder
String 字符串常量存储在常量区,每次追加操作会创建新的对象: StringBuffer 字符串变量 线程安全 在堆上创建,每次追加操作在原对象上进行操作: 速度 StringBuffer ...
- Java中 StringBuffer StringBuilder String 区别
String 字符串常量 不可变 使用字符串拼接时是不同的2个空间 StringBuffer 字符串变量 可变 线程安全 字符串拼接直接在字符串后追加 StringBui ...
- Java基础(33):StringBuilder的方法与应用实例(String相关类)
Java 中的 StringBuilder 类的常用方法 重要的事情说三遍: 在需要频繁对字符串进行修改操作时使用 StringBuilder 的效率比 String 要高 在需要频繁对字符串进行修改 ...
- Java基础——StringBuffer和StringBuilder
本节讲述2个字符串容器的区别 StringBuffer和StringBuilder区别: 1.相同点 两者都是容器(可变的字符序列),都可以对字符串进行基本的“增删改查”操作. 2.不同点 Strin ...
- java ——String , StringBuffer, StringBuilder类
一.String类概述 1.String对象一旦创建就不能改变. 2.字符串常量池. 字符串常量池的特点:池中有则直接使用,池中没有则创建新的字符串常量. 例1: “==” 比较两个对象是否引用同一 ...
- java数据库连接池技术原理(浅析)
在执行数据库SQL语句时,我们先要进行数据连接:而每次创建新的数据库的连接要消耗大量的资源,这样,大家就想出了数据库连接池技术.它的原理是,在运行过程中,同时打开着一定数量的数据库连接,形成数据连接池 ...
随机推荐
- Python 下载依赖包环境经常失败超时解决方法
人生苦短,我用python!为什么很多人喜欢用python,因为包多呀,各种调包.但是调包有的时候也调的闹心,因为安装包不是失败就是很慢,很影响自己的工作进度,这里给出一个pip快速安装工具包的办法, ...
- 大数据 Hibernate
大数据 Hibernate - 国内版 Binghttps://cn.bing.com/search?FORM=U227DF&PC=U227&q=%E5%A4%A7%E6%95%B0% ...
- apache环境.htaccess设置301跳转及常用.htaccess技巧整理
apache环境.htaccess设置301跳转及常用.htaccess技巧整理 无论是Nginx,还是Apache都各自有优势,对于我们普通用户而言基本上也没有多大的区别.在虚拟主机环境中,基本上都 ...
- Sword 位运算取余操作
/* 位运算取余操作 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include ...
- 【SpringBoot】SpringBoot 国际化(七)
本周介绍SpringBoot项目的国际化是如何处理的,阅读本章前请阅读[SpringBoot]SpringBoot与Thymeleaf模版(六)的相关内容 国际化原理 1.在Spring中有国际化Lo ...
- C++内存管理1-64位系统运行32位软件会占用更多的内存吗?
随着大容量内存成为电脑平台常规化的配置,在配置组装机时很多的用户都会选择8GB甚至是16GB的容量规格内存使用在自己的机器上,如果要将这8GB甚至是16GB的内容在系统使用时能充分利用起来的话,你平台 ...
- SpringBoot处理异常方式
SpringBoot提供了多种处理异常方式,以下为常用的几种 1. 自定义错误异常页面 SpringBoot默认的处理异常的机制:SpringBoot默认的已经提供了一套处理异常的机制.一旦程序中出现 ...
- fedora清理旧内核
先查看已安装的内核: rpm -qa|grep kernel 然后查看下当前在用的内核: uname -r 最后是删除内核: yum remove xxxx
- [转]Ubuntu18.04隐藏顶栏与侧栏
链接地址:https://blog.csdn.net/liu_jiangwen/article/details/85215297
- Dockerfile & Docker Swarm & Docker Stack & Docker Compose
Dockerfile 通俗地讲,它是为了指导单个镜像从无到有的构建过程.如果你镜像是从Docker registry上面拉下来的,那就用不到这个文件:如果你是自己的应用,想打包成镜像,那就需要这个文件 ...