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. 防止同一IP多次请求攻击

    防止同一IP多次请求攻击 防止入侵者,通过死循环同一时间批量向服务器请求数据,导致服务器内存开销不断膨胀,最后直接瘫痪. 一. 新增一个spring的拦截器 , 拦截所有请求 <mvc:inte ...

  2. Android Studio 教程

    Android Studio 超详细安装教程 http://dkylin.com/archives/2019/android-studio-installation.html Android Stud ...

  3. Java13新特性 -- switch表达式动态CDS档案(动态类数据共享归档)

    支持在Java application执行之后进行动态archive.存档类将包括默认的基础层CDS存档中不存在的所有已加载的应用程序和库类.也就是说,在Java 13中再使用AppCDS的时候,就不 ...

  4. OSI七层模型、TCP/IP五层模型

    OSI网络互连的七层框架:物理层.数据链路层.网络层.传输层.会话层.表示层.应用层: <1>应用层 OSI参考模型中最靠近用户的一层,是为计算机用户提供应用接口,为用户直接提供各种网络服 ...

  5. Flask 上传下载文件

    上传文件示例代码 #encoding:utf8 from werkzeug.utils import secure_filename from flask import Flask,render_te ...

  6. Dart入门

    要学Flutter必先学Dart,Dart和Java的语法很像,学过Java的人很快就能入手 Dart下载地址https://dart.dev/get-dart VSCode下载地址https://c ...

  7. Redis 分布式锁的正确实现方式(Java版)[转]

    本文来源: https://www.cnblogs.com/linjiqin/p/8003838.html 前言 分布式锁一般有三种实现方式: 数据库乐观锁: 基于Redis的分布式锁: 基于ZooK ...

  8. 为什么地址空间分配粒度为64K?Why is address space allocation granularity 64K?

    您可能想知道为什么VirtualAlloc在64K边界分配内存,即使页面粒度为4K. 你有Alpha AXP处理器,感谢你. 在Alpha AXP上,没有“加载32位整数”指令.要加载32位整数,实际 ...

  9. python办公自动化(一)PPTX

    简介: python-pptx是python处理PPT的一个库,注重的是读和写,无法导出,没有渲染功能. 办公自动化,说的是大了一点,但是最常见的office三件套,word,excel,ppt.这还 ...

  10. 从原生Android 跳转到hbuilder项目

    原文地址:https://blog.csdn.net/pentablet/article/details/80277157 前段时间做项目,需要把别人做的hbuilder项目,添加到自己的app中,找 ...