博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java中String、StringBuffer、StringBuilder的区别
阅读量:6630 次
发布时间:2019-06-25

本文共 5524 字,大约阅读时间需要 18 分钟。

阅读目录

 

Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串

0. 不当用法

String result = "";  for (String s : hugeArray) {      result = result + s;  }

不要使用String类的"+"来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则

1. String类封装的字符串是不可变的

字符串是由若干个字符线性排列组成的,String类的关键源码如下

public final class String    implements java.io.Serializable, Comparable
, CharSequence { /** The value is used for character storage. */ private final char value[];//final类型char数组//省略其他代码…………}

因为有“final”修饰符,所以可以String类封装的字符串是不可变的。那么增删改是怎么实现的呢?下面是字符串截取的关键源码

public String substring(int beginIndex) {        if (beginIndex < 0) {            throw new StringIndexOutOfBoundsException(beginIndex);        }        int subLen = value.length - beginIndex;        if (subLen < 0) {            throw new StringIndexOutOfBoundsException(subLen);        }       //当对原来的字符串进行截取的时候(beginIndex >0),返回的结果是新建的对象        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);    }

可以看到截取源码是生成了一个新的String对象返回的。

所以,在对String类型的字符串进行大量“插入”和“删除”操作时会产生大量的临时变量。

既然String类封装的字符串是不可变的,那么是否应该有一个类来封装可变数组。答案是有的,StringBuilder与StringBuffer封装类都是可变的。

2. 如何做到封装数组可变

StringBuilder与StringBuffer都继承自AbstractStringBuilder抽象类,在AbstractStringBuilder中也是使用字符数组保存字符串,其关键代码如下

abstract class AbstractStringBuilder implements Appendable, CharSequence {    /**     * The value is used for character storage.     */    char[] value;//一个char类型的数组,非final类型,这一点与String类不同    /**     * This no-arg constructor is necessary for serialization of subclasses.     */    AbstractStringBuilder() {    }    /**     * Creates an AbstractStringBuilder of the specified capacity.     */    AbstractStringBuilder(int capacity) {        value = new char[capacity];//构建了长度为capacity大小的数组    }//其他代码省略…………}

StringBuffer类实现代码如下

public final class StringBuffer    extends AbstractStringBuilder    implements java.io.Serializable, CharSequence{   /**     * Constructs a string buffer with no characters in it and an     * initial capacity of 16 characters.     */    public StringBuffer() {        super(16);//创建一个默认大小为16的char型数组    }    /**     * Constructs a string buffer with no characters in it and     * the specified initial capacity.     *     * @param      capacity  the initial capacity.     * @exception  NegativeArraySizeException  if the {
@code capacity} * argument is less than {
@code 0}. */ public StringBuffer(int capacity) { super(capacity);//自定义创建大小为capacity的char型数组 }//省略其他代码…………

可以看到StringBuffer创建字符串对象默认的大小是16,当然也可以传入数组大小。

下面列下StringBuffer的用法

public class Test{  public static void main(String args[]){    StringBuffer sBuffer = new StringBuffer("hello");    sBuffer.append(" ");    sBuffer.append("world");    System.out.println(sBuffer);   }}

输出

1
hello world

下面看源码分析下append函数,来看下如何做到长度可变

public AbstractStringBuilder append(String str) {        if (str == null)            return appendNull();        int len = str.length();       //调用下面的ensureCapacityInternal方法        ensureCapacityInternal(count + len);        str.getChars(0, len, value, count);        count += len;        return this;    }private void ensureCapacityInternal(int minimumCapacity) {        // overflow-conscious code        if (minimumCapacity - value.length > 0)           //调用下面的expandCapacity方法实现“扩容”特性            expandCapacity(minimumCapacity);    }   /**     * This implements the expansion semantics of ensureCapacity with no     * size check or synchronization.     */    void expandCapacity(int minimumCapacity) {       //“扩展”的数组长度是按“扩展”前数组长度的2倍再加上2 byte的规则来扩展        int newCapacity = value.length * 2 + 2;        if (newCapacity - minimumCapacity < 0)            newCapacity = minimumCapacity;        if (newCapacity < 0) {            if (minimumCapacity < 0) // overflow                throw new OutOfMemoryError();            newCapacity = Integer.MAX_VALUE;        }        //将value变量指向Arrays返回的新的char[]对象,从而达到“扩容”的特性        value = Arrays.copyOf(value, newCapacity);    }

可以看到空间扩展室友copyOf函数实现:

public static char[] copyOf(char[] original, int newLength) {        //创建长度为newLength的char数组,也就是“扩容”后的char 数组,并作为返回值        char[] copy = new char[newLength];        System.arraycopy(original, 0, copy, 0,                         Math.min(original.length, newLength));        return copy;//返回“扩容”后的数组变量    }

3. StringBuilder与StringBuffer 区别

AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法,StringBuilder和StringBuffer的方法实现基本上一致,不同的是StringBuffer类的方法前多了个synchronized关键字,即StringBuffer是线程安全的。

public synchronized StringBuffer reverse() {    super.reverse();    return this;}public int indexOf(String str) {    return indexOf(str, 0);        //存在 public synchronized int indexOf(String str, int fromIndex) 方法}

(1)append,insert,delete方法最根本上都是调用System.arraycopy()这个方法来达到目的

(2)substring(int, int)方法是通过重新new String(value, start, end - start)的方式来达到目的。因此,在执行substring操作时,StringBuilder和String基本上没什么区别。

4. 使用场景

如果是多线程环境下涉及到共享变量的插入和删除操作,StringBuffer则是首选。如果是非多线程操作并且有大量的字符串拼接,插入,删除操作则StringBuilder是首选。毕竟String类是通过创建临时变量来实现字符串拼接的,耗内存还效率不高,怎么说StringBuilder是通过JNI方式实现终极操作的。

5. 总结

  • String类型的字符串对象是不可变的,一旦String对象创建后,包含在这个对象中的字符系列是不可以改变的,直到这个对象被销毁。
  • StringBuilder和StringBuffer类型的字符串是可变的,不同的是StringBuffer类型的是线程安全的,而StringBuilder不是线程安全的
  • 如果是多线程环境下涉及到共享变量的插入和删除操作,StringBuffer则是首选。如果是非多线程操作并且有大量的字符串拼接,插入,删除操作则StringBuilder是首选。
  • 如果要操作少量的数据,用String;单线程操作大量数据,用StringBuilder;多线程操作大量数据,用StringBuffer。
本文转自jihite博客园博客,原文链接:http://www.cnblogs.com/kaituorensheng/p/8168024.html,如需转载请自行联系原作者
你可能感兴趣的文章
Java开发工具IntelliJ IDEA使用教程:创建新的Andriod项目
查看>>
css续集1
查看>>
http协议中的header详解
查看>>
使用common-codec进行md5加密
查看>>
MaxCompute应用限制整理
查看>>
聊聊sentinel的SimpleHttpCommandCenter
查看>>
Linux学习笔记第二周第四次课(2月1日)
查看>>
sqlserver用sql语句创建及查询链接服务器所有的数据库、用户和表
查看>>
JAVA for循环
查看>>
https证书一年多少钱?
查看>>
linux Screen的安装与简单应用
查看>>
【前端开发】JSON 完全自学手册
查看>>
iptables
查看>>
记世界上第一台运行图形化用户界面操作系统的微型电脑
查看>>
DEV报表基础教程(二)
查看>>
Spark的transformation 和 action的操作学习笔记
查看>>
socket远程控制(练手)___源码
查看>>
OPPO F9配置曝光 配备6.3英寸19.5:9触摸屏
查看>>
使用Vue.Js结合Jquery Ajax加载数据的两种方式
查看>>
优化IIS7.5支持10万个同时请求的配置方法_win服务器
查看>>