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. vue-devtools 获取到 vuex store 和 Vue 实例的?

    vue-devtools 获取到 vuex store 和 Vue 实例的? https://github.com/vuejs/vue-devtools       安装了 vue-devTools ...

  2. iOS逆向(五)-ipa包重签名

    为什么要重签名? 1.在没有源代码的情况下,你已经对某个应用进行了资源修改(比如修改了启动图或图标等).修改完成以后,如果想要让APP可以正常使用,该APP一定要重新签名然后压缩成IPA文件. 2.如 ...

  3. 支付宝小程序开发——H5跳转到小程序(获取小程序页面的链接)

    前言: 这个问题支付宝小程序官方文档并没有专门说明,钉钉群的官方技术支持给了个开发者社区的帖子,详见:如何跳转小程序. 如果配置的页面没有参数还好,不会出问题,如果有参数,很可能配出来的链接无法正常获 ...

  4. (mysql)找不到请求的.Net Framework Data Provider。可能没有安装

    webconfig配置以下节点(注意版本号) 将下面代码放在machine.config中文件,如何Web.config文件没有配置,需要添加 <system.data> <DbPr ...

  5. Ubuntu 16.04 catkin_make 常见操作

    参考博客:https://answers.ros.org/question/54178/how-to-build-just-one-package-using-catkin_make/ 1. catk ...

  6. (转载)Pytorch中的仿射变换(affine_grid)

    转载于:Pytorch中的仿射变换(affine_grid) 参考:详细解读Spatial Transformer Networks (STN) 假设我们有这么一张图片:   下面我们将通过分别通过手 ...

  7. html中测试div、ul和li、table排列多个块

    前面有三篇博文测试了这三种方式,一.相关博文:LODOP问答部分链接.该文用的是div定位,用的是所有小div相对于大div进行定位,大的div设置relative定位,小的设置absolute相对于 ...

  8. scala 样例类

    一.case class 的特征 package com.jason.qianfeng case class Message(sender: String, receiver: String, bod ...

  9. 五、Spring中的@Import注解

    一.使用@Import注解导入组件 @Import注解的作用是给容器中导入组件,回顾下我们给容器中导入组件的方式,可以通过Spring的xm配置方式,可以通过注解,如@Component等,也可以通过 ...

  10. 深度学习-深度强化学习(DRL)-Policy Gradient与PPO笔记

    Policy Gradient 初始学习李宏毅讲的强化学习,听台湾的口音真是费了九牛二虎之力,后来看到有热心博客整理的很细致,于是转载来看,当作笔记留待复习用,原文链接在文末.看完笔记再去听一听李宏毅 ...