zoukankan      html  css  js  c++  java
  • String、StringBuffer、StringBuilder的区别

    ##总结:

      String:底层代码是一个用final修饰的char数组,是一个不可变的字符串,因此是线程安全的。对String字符串进行改变时,都会产生一个新的String对象,然后将指针指向String对象,影响系统性能,适用于少量字符串操作的情况。String初始化时,除了用构造函数进行初始化,还可以直接赋值(可以赋空值)。

      StringBuilder:是可变字符串,支持并发操作,是线程安全的,效率低;适用于多线程下在字符串缓冲区进行大量操作的情况。StringBuilder只能用构造函数的形式来初始化(不可以赋空值)。

        StringBuffer修改字符串的原理:首先创建一个stringbuffer对象,然后调用append方法,最后调用toString方法。使用stringbuffer类时,每次都是对stringbuffer对象本身进行操作,不会生成新对象并改变对象的引用。

      StringBuilder:是可变字符序列,不支持并发操作,是线程不安全的,效率高;适用于单线程下在字符缓冲区进行大量操作的情况。StringBuilder只能用构造函数进行初始化(不可以赋空值)。

      三者的运行速度:StringBuilder>StringBuffer>String

        String为字符串常量,而StringBuffer和StringBuilder均为字符串变量,即String对象一旦创建,该对象就是不可更改的,但后两者的对象是变量,是可以更改的。

        Java中对象String对象进行的操作,实际上是一个不断创建新对象并且将旧对象回收的过程,所以执行速度很慢。在单线程下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全,而StringBuffer每次都需要判断锁,效率相对较低。

      StringBuilder和StringBuffer都继承于AbstractStringBuilder类,实现了Serializable序列化接口、Appendable接口及CharSequence接口。

    一、String

      1.string的底层代码为一个用final修饰的char数组,这就意味着定义一个string字符串后,该字符串的内容是不可变的。

    1 public final class String
    2     implements java.io.Serializable, Comparable<String>, CharSequence {
    3     private final char value[];  //String其实就是用char[]实现的。
    4     private int hash; // Default to 0 //缓存字符串的hash Code,默认值为 0
    5     //String类的内部就是维护了一个char数组
    6     private static final long serialVersionUID = -6849794470754667710L;
    7     private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];

      因为string实现了Serializable接口,所以支持序列化(把对象转换为字节序列的过程)和反序列化(把字节序列恢复为对象的过程)。Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。

      2.构造方法

        使用字符数组、字符串构造一个string

        使用字节数组构造一个string

        使用StringBuffer和StringBuilder构造一个string

     1 public String(char value[]) {
     2         this.value = Arrays.copyOf(value, value.length);
     3     }
     4     public String(char value[], int offset, int count) {
     5         if (offset < 0) {
     6             throw new StringIndexOutOfBoundsException(offset);
     7         }
     8         if (count < 0) {
     9             throw new StringIndexOutOfBoundsException(count);
    10         }
    11         if (offset > value.length - count) {
    12             throw new StringIndexOutOfBoundsException(offset + count);
    13         }
    14         this.value = Arrays.copyOfRange(value, offset, offset+count);
    15     }

        这两个构造方法都用到了Arrays工具类的copyOf方法,在这两个方法里面都调用了System.arraycopy方法;因为System.arraycopy是一个系统本地方法,所以这个方法的效率很高,所以在构造string时效率也很高。

      3.compareTo方法(因为string实现了Comparable接口,所以必须实现compareTo方法)

     1 public int compareTo(String anotherString) {
     2         int len1 = value.length;
     3         int len2 = anotherString.value.length;
     4         int lim = Math.min(len1, len2);
     5         char v1[] = value;
     6         char v2[] = anotherString.value;
     7         int k = 0;
     8         while (k < lim) {
     9             char c1 = v1[k];
    10             char c2 = v2[k];
    11             if (c1 != c2) {
    12                 return c1 - c2;
    13             }
    14             k++;
    15         }
    16         return len1 - len2;
    17     }

      4.length,charAt方法

     1 public int length() {
     2         return value.length;
     3     }
     4     public boolean isEmpty() {
     5         return value.length == 0;
     6     }
     7     public char charAt(int index) {
     8         if ((index < 0) || (index >= value.length)) {
     9             throw new StringIndexOutOfBoundsException(index);
    10         }
    11         return value[index];
    12     }

      5.getBytes方法

        调用了StringCoding.encode方法,encode方法调用另外一个重载的方法。

     1 static byte[] encode(char[] ca, int off, int len) {
     2         String csn = Charset.defaultCharset().name();
     3         try {
     4             return encode(csn, ca, off, len);
     5         } catch (UnsupportedEncodingException x) {
     6             warnUnsupportedCharset(csn);
     7         }
     8         try {
     9             return encode("ISO-8859-1", ca, off, len);
    10         } catch (UnsupportedEncodingException x) {
    11             MessageUtils.err("ISO-8859-1 charset not available: "+ x.toString());
    12             System.exit(1);
    13             return null;
    14         }
    15     }

    二、StringBuffer

      1.StringBuffer继承于AbstracctStringBuilder抽象类,实现了Serializable接口和CharSequence接口。

    1 public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
    2 static final long serialVersionUID = 3388685877147921107L;
    3 public StringBuffer() {
    4         super(16);
    5     }

      2.StringBuffer初始化及扩容机制

        1)StringBuffer()的初始容量为16,当该对象的实体存放的字符长度大于16时,实体容量就会自动增加。StringBuffer对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。

        2)StringBuffer(int size)可以指定分配给该对象的实体的初始容量参数为参数size指定的字符个数。当该对象的实体存放的字符长度大于size个字符时,实体的容量就会自动增加,以便存放所增加的字符。

        3)StringBuffer(String s)指定给对象的实体的初始容量为参数字符串s的长度额外再加16个字符。当该对象的实体存放的字符序列长度大于size个字符时,实体的容量自动增加。

     1 public StringBuffer(String str) {
     2 //这个执行父类的带参构造函数AbstractStringBuilder(int capacity) 
     3         super(str.length() + 16);
     4         append(str);
     5     }
     6 //append 是用 synchronized 修饰的,所以是线程安全的
     7 public synchronized StringBuffer append(String str) {  
     8         //执行父类的append(str)  
     9         super.append(str);  
    10         return this;  
    11 } //父类 AbstractStringBuilder 的 append 方法

      扩容算法:使用append方法在字符串后面追加内容时,如果长度超过了子符串存储空间大小就需要进行扩容:创建新的存储空间更大的字符串,将旧的复制过去;再进行字符串append添加时,会先计算添加后字符串的大小,传入一个方法:ensureCapacityInternal这个方法进行是否扩容的判断,需要扩容就调用expandCapacity方法进行扩容,尝试将新容量扩大为原来大小的2倍+2,if判断一下,容量如果还不够,直接扩充到需要的容量大小。

      添加字符串过程:

        -->先检查内部char[]数组是否需要扩容;

        -->如果需要扩容则进行扩容,然后将原来的元数据copy到新数组中;

        -->再将新添加的元数据加入到新数组中。

     1 public AbstractStringBuilder append(String str) {
     2         if (str == null)
     3             return appendNull();
     4         int len = str.length();
     5         //检查char[]数组是否需要扩容,扩容,并将原来的数据copy进去新扩容的数组中
     6         ensureCapacityInternal(count + len);
     7         //将新添加的数据添加到StringBuilder中的char[]数组中,实现字符串的添加
     8         str.getChars(0, len, value, count);
     9         count += len;
    10         return this;
    11     }
    12 /**
    13 *元数组char[]的扩容过程
    14 */
    15     void expandCapacity(int minimumCapacity) {
    16         int newCapacity = value.length * 2 + 2;
    17         if (newCapacity - minimumCapacity < 0)
    18             newCapacity = minimumCapacity;
    19         if (newCapacity < 0) {
    20             if (minimumCapacity < 0) // overflow
    21                 throw new OutOfMemoryError();
    22             newCapacity = Integer.MAX_VALUE;
    23         }
    24         value = Arrays.copyOf(value, newCapacity);
    25     }
    26 /**
    27 *扩容实现
    28 */
    29    public static char[] copyOf(char[] original, int newLength) {
    30         char[] copy = new char[newLength];
    31         System.arraycopy(original, 0, copy, 0,
    32                          Math.min(original.length, newLength));
    33         return copy;
    34     }
    35   if (str == null)
    36             return appendNull();
    37         int len = str.length();
    38         //检查char[]数组是否需要扩容,扩容,并将原来的数据copy进去新扩容的数组中
    39         ensureCapacityInternal(count + len);
    40         //将新添加的数据添加到StringBuilder中的char[]数组中,实现字符串的添加
    41         str.getChars(0, len, value, count);
    42         count += len;
    43         return this;
    44 }

    三、StringBuilder

        

       

  • 相关阅读:
    JQuery--常用选择器总结
    ASP.NET MVC- ActionFilter的使用
    C#--DataTable与Dataset的互相转换
    C#--List转DataTable(或DataSet)
    JavaScript--遍历table中的tr存对象
    JavaScript--删除Table中当前行
    JavaScript--判断字符是否为空
    JavaScript--为对象动态添加属性和值
    asp.net mvc 单图片上传
    asp.net mvc 多图片上传
  • 原文地址:https://www.cnblogs.com/HuiH/p/11729560.html
Copyright © 2011-2022 走看看