JDK源码分析系列---String,StringBuilder,StringBuffer

1.String

public final class String implements java.io.Serializable, Comparable<String>, CharSequence { //存储字符,final修饰
    private final char value[]; //缓存hash code,默认0
    private int hash; //序列号
    private static final long serialVersionUID = -6849794470754667710L; //声明可序列化字段
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0]; }

 

1.1 基本属性

  • char value[],用来存储字符串对象的字符数组
  • int hash,用来缓存字符串的hash code,默认值为0
  • long serialVersionUID,用来序列化的序列版本号
  • ObjectStreamField[],可序列化类的字段说明

1.2 经常使用构造器

public String() { this.value = "".value; }

 

初始化新建立的对象,表示空字符串""。请注意,此构造函数是不须要使用的,由于字符串是不可变的.
String str = new String(); 本质上是建立了一个空的字符数组,str的长度为0 html

public String(String original) { this.value = original.value; this.hash = original.hash; } 

 

初始化新建立的对象,表示和参数同样的字符串,换句话说是建立了和参数同样的对象副本,除非须要显示的声明副本,不然该构造函数是不须要的,由于字符串是不可变的java

public String(StringBuffer buffer) { synchronized(buffer) { this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } }

 

把StringBuffer的内容复制到String对象中,随后修改StringBuffer对象的值,并不会影响String对象数组

public String(StringBuilder builder) { this.value = Arrays.copyOf(builder.getValue(), builder.length()); }

 

把StringBuilder的内容复制到String对象中,随后修改StringBuilder的值,并不会影响String对象;
此构造函数是为了把StringBuilder转移到String对象,可是推荐使用StringBuilder的toString()方法,由于运行更快缓存

1.3 经常使用方法

//返回字符串的长度
public int length() { return value.length; } //比较两个String值是否相等
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } //生成hash code
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }

 

equals方法的判断流程:
  • 首先判断两个对象是否相同,若相同返回true;若不一样,下一步
  • 判断参数是否为String对象,若不是,返回false;如果,下一步
  • 判断两个String的长度是否相等,若不是,返回false;如果,下一步
  • 按字符数组索引依次比较字符,若是有任一不相同,返回false,不然返回true

这里能够看到equals方法的实现也是调用了==来比较对象是否相同,所以在讨论equals和==区别的时候 要全面分析.安全

1.2 为何说String是不可变对象?

存储字符的数组value[]是final修饰的,值不可更改.多线程

2. AbstractStringBuilder

可变的字符序列,StringBuilder和StringBuffer都继承了该类,要了解StringBuilder和StringBuffer首先先了解AbstractStringBuilder.app

2.1 基本属性

abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * The value is used for character storage. */
    char[] value; /** * The count is the number of characters used. */
    int count; }

 

char[] value: 存储字符的数组
int count: 存储的字符的数量ide

2.2 构造器

/** * 无参构造器,用于子类序列化 */ AbstractStringBuilder() { } /** * 指定字符数组容量 */ AbstractStringBuilder(int capacity) { value = new char[capacity]; }

 

2.3 经常使用方法

/** * 返回字符的数量 */ @Override public int length() { return count; } /** * 返回当前可存储字符的最大数量,即容量 */
public int capacity() { return value.length; } /** * 保证当前容量大于等于指定的最小数量minimumCapacity,会调用扩容方法 */
public void ensureCapacity(int minimumCapacity) { if (minimumCapacity > 0) ensureCapacityInternal(minimumCapacity); } /** * 扩容,只有minimumCapacity大于当前容量,才会copy数组扩容 */
private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code
    if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } /** * 当前对象拼接字符串str * 若是参数为null,那么最终字符串为"null",若是参数类型为boolean,那么返回的是"true"或"false" * 例1: "abc".append(null) = "abcnull" * 例2: "abc".append(false) = "abcfalse" */
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; }

 

3. StringBuilder

可变的字符序列,非线程安全,StringBuilder和StringBuffer的实现方法很类似,区别在因而否线程安全,在单线程的状况下可以使用StringBuilder,由于它比StringBuffer运行更快.StringBuilder继承了AbstractStringBuilder类.函数

3.1 基本属性

继承父类ui

3.2 构造器

/** * 默认容量16 */
public StringBuilder() { super(16); } /** * 指定初始容量 */
public StringBuilder(int capacity) { super(capacity); } /** * 把String字符串初始化到对象中,容量变为str的长度+16 */
public StringBuilder(String str) { super(str.length() + 16); append(str); } /** * 把字符初始化到对象中,容量变为字符的长度+16 */
public StringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq); }

 

3.3 经常使用方法

同父类

4. StringBuffer

可变的字符序列,线程安全,StringBuffer继承了AbstractStringBuilder类.

4.1 基本属性

继承父类,同时还有属性toStringCache
这里涉及到一个关键字transient,其做用是让某些被修饰的成员属性变量不被序列化,为何不须要序列化呢?主要是由于这个变量可能为null,也可能非空,不能准确的表明StringBuffer的属性.因此没有必要序列化,也节省了空间.

public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence{ /** * 最后一次调用toString返回值的缓存 * 当StringBuffer被修改时该缓存被清除 */
    private transient char[] toStringCache; /** 序列号 */
    static final long serialVersionUID = 3388685877147921107L; }

 

4.2 构造器

同StringBuilder

4.3 经常使用方法

与StringBuilder方法基本相同,区别在于在StringBuilder的方法上加了synchronized锁. 不一样的地方还包括每一个修改对象的方法,好比append方法都会清除toStringCache缓存.

@Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } @Override public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }

 

  1. 在调用toString方法的时候,会先判断缓存toStringCache是否存在,若是不存在,那么把当前对象赋值给toStringCache,而后获得toStringCache的字符串;若是toStringCache已经存在,那么直接读取缓存的字符串.
  2. toStringCache是否存在依赖于StringBuffer对象是否被修改,若是被修改了,那么缓存被清空.

5.总结

  1. String,StringBuilder,StringBuffer这三个类均可以建立和操做字符串;
  2. 不一样点在于String是不可变的,不存在线程安全问题;StringBuilder和StringBuffer字符串是可变的,StringBuilder线程不安全,StringBuffer线程安全;
  3. 对于简单的字符串赋值和拼接操做,可以使用String
  4. 对于字符串频繁修改和拼接操做,不建议使用String,由于每次操做都须要建立一个String对象,单线程推荐使用StringBuilder,多线程推荐使用StringBuffer.

原文出处:https://www.cnblogs.com/iceblow/p/11159120.html

相关文章
相关标签/搜索