您的位置:首页 > Web前端

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

2019-07-09 18:06 1571 查看

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

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

初始化新创建的对象,表示和参数一样的字符串,换句话说是创建了和参数一样的对象副本,除非需要显示的声明副本,否则该构造函数是不需要的,因为字符串是不可变的

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

1.2 为什么说String是不可变对象?

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

2. AbstractStringBuilder

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

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:使用的字符的数量

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("def") = "abcdef"
*/
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 基本属性

继承父类

3.2 构造器

public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{

/**
*序列号
*/
static final long serialVersionUID = 4383685877147921099L;

/**
* 默认容量16
* initial capacity of 16 characters.
*/
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 基本属性

继承父类,同时还有以下属性

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锁.

5.总结

综上所述,可以得出相同点是:都可以创建字符串,不同在于String是不可变的,不存在线程安全问题;StringBuilder和StringBuffer字符串是可变的,StringBuilder线程不安全,适合单线程使用,StringBuffer线程安全,适合多线程;对于频繁需要字符串的拼接操作时,不建议使用String,因为每次都需要创建一个String对象.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: