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原理浅析的更多相关文章

  1. Java基础-StringBuffer类与StringBuilder类简介

    Java基础-StringBuffer类与StringBuilder类简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.StringBuffer类 在学习过String类之后 ...

  2. Java基础(四) StringBuffer、StringBuilder原理浅析

    StringBuilder与StringBuffer作用就是用来处理字符串,但String类本身也具备很多方法可以用来处理字符串,那么为什么还要引入这两个类呢? 关于String的讲解请看Java基础 ...

  3. Java基础(五) final关键字浅析

    前面在讲解String时提到了final关键字,本文将对final关键字进行解析. static和final是两个我们必须掌握的关键字.不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提 ...

  4. Java String StringBuffer StringBuilder

    String  字符串常量存储在常量区,每次追加操作会创建新的对象: StringBuffer  字符串变量  线程安全 在堆上创建,每次追加操作在原对象上进行操作:  速度 StringBuffer ...

  5. Java中 StringBuffer StringBuilder String 区别

    String       字符串常量   不可变  使用字符串拼接时是不同的2个空间 StringBuffer  字符串变量   可变   线程安全  字符串拼接直接在字符串后追加 StringBui ...

  6. Java基础(33):StringBuilder的方法与应用实例(String相关类)

    Java 中的 StringBuilder 类的常用方法 重要的事情说三遍: 在需要频繁对字符串进行修改操作时使用 StringBuilder 的效率比 String 要高 在需要频繁对字符串进行修改 ...

  7. Java基础——StringBuffer和StringBuilder

    本节讲述2个字符串容器的区别 StringBuffer和StringBuilder区别: 1.相同点 两者都是容器(可变的字符序列),都可以对字符串进行基本的“增删改查”操作. 2.不同点 Strin ...

  8. java ——String , StringBuffer, StringBuilder类

    一.String类概述 1.String对象一旦创建就不能改变. 2.字符串常量池. 字符串常量池的特点:池中有则直接使用,池中没有则创建新的字符串常量. 例1: “==”  比较两个对象是否引用同一 ...

  9. java数据库连接池技术原理(浅析)

    在执行数据库SQL语句时,我们先要进行数据连接:而每次创建新的数据库的连接要消耗大量的资源,这样,大家就想出了数据库连接池技术.它的原理是,在运行过程中,同时打开着一定数量的数据库连接,形成数据连接池 ...

随机推荐

  1. 试图从目录中执行 CGI、ISAPI 或其他可执行程序

    首先来看我遇到问题时的情况,直接上图!   从上图的错误提示信息可以看出,是权限不够,被拒绝访问,开始我以为是我的程序的php程序的原因,但是其他站点没事啊,就对这个站点的权限重新分配了下,给了最高权 ...

  2. <c:forEach>, <c:forTokens> 标签

    这些标签封装了Java中的for,while,do-while循环. 相比而言,<c:forEach>标签是更加通用的标签,因为它迭代一个集合中的对象. <c:forTokens&g ...

  3. SQL 对比,移动累计

    数据对比 两种常用模型 1.对比下一行,判断增长.减少.维持现状 -- 建表 drop table sales create table sales( num int, soc int ); inse ...

  4. IntelliJ IDEA Error:(24, 35) java: 常量字符串过长

    在转换一个JSON转Java对象是 idea 编译不通过  提示:Error:(24, 35) java: 常量字符串过长 File -> Settings -> Build,Execut ...

  5. shell基础知识5-函数

    函数的定义 function fname(){ } 或者 function_name(){ } 对于简单的函数,甚至可以是这样做 fname() { statement; } 函数调用 直接写函数名即 ...

  6. Zabbix使用第三方API短信报警

    之前试过邮件告警,微信告警.但是,对于一些企业的重要业务服务器,可能是存放在隔离的内网中的,无法正常连接外网.这个时候,就有必要考虑一下使用短信告警.以下这个其实还是需要服务器能够连接到外网的,但是我 ...

  7. linux 程序失败自动重启

    最近写了一个spark streaming 程序,但是程序跑着跑着就报错了,而且不会自动重启,以下脚本实现了程序失败自动重启 基本原理:查看程序日志文件是否有ERROR或Exception字样,有说明 ...

  8. python数据分析1

    1 数据分析三要素 从下图可以清晰看出 感觉不怎么方便把图放上去,如果需要原图的私信我吧. 2 所谓修炼指南 (1)从思维到工具再到实践 (2)只有把只是抓换为自己的语言,才真正编程我们自己的东西 3 ...

  9. ActiveMQ 安装方法

    1. 打开浏览器,访问网址 http://activemq.apache.org/components/classic/download/ ,下载最新的版本,当前最新版本为5.15.9,根据Activ ...

  10. Spring Boot 项目的 API 接口防刷

    首先是写一个注解类 拦截器中实现 注册到springboot中 在Controller中加入注解 说明:使用了注解的方式进行对接口防刷的功能,非常高大上,本文章仅供参考 一,技术要点:springbo ...