【Java 入门】String,StringBuffer 和 StringBuilder

用户头像
HQ数字卡
关注
发布于: 2020 年 12 月 21 日

基本介绍

字符串广泛应用编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。



String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了。



Q: 为什么说Sting类是可不变的呢?

A: 我们String的底层实现,实际上是由final char[]来存储。代码如下:



public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}

/**
* Allocates a new {@code String} that contains characters from a subarray
* of the character array argument. The {@code offset} argument is the
* index of the first character of the subarray and the {@code count}
* argument specifies the length of the subarray. The contents of the
* subarray are copied; subsequent modification of the character array does
* not affect the newly created string.
*
* @param value
* Array that is the source of characters
*
* @param offset
* The initial offset
*
* @param count
* The length
*
* @throws IndexOutOfBoundsException
* If the {@code offset} and {@code count} arguments index
* characters outside the bounds of the {@code value} array
*/
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}


}



当我们对字符串进行频繁修改的时候,一般使用 StringBuffer 和 StringBuilder 类。



和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。



Q: 为什么?

A: 看代码

  • StringBuffer使用synchronized关键字修饰,保障线程安全。

  • 使用toStringCache保障线程安全,并提高返回效率。

  • 使用共享String提升速度



StringBuffer 精简核心代码

public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
@Override
public synchronized StringBuffer append(char c) {
toStringCache = null;
super.append(c);
return this;
}
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
}



StringBuilder代码如下:



public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
}



abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
/**
* Appends the specified string to this character sequence.
* <p>
* 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.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at
* index <i>k</i> in the new character sequence is equal to the character
* at index <i>k</i> in the old character sequence, if <i>k</i> is less
* than <i>n</i>; otherwise, it is equal to the character at index
* <i>k-n</i> in the argument {@code str}.
*
* @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;
}
}



实际开发建议

Synchronized classes Vector, Hashtable, Stack and StringBuffer should not be used



Early classes of the Java API, such as Vector, Hashtable and StringBuffer, were synchronized to make them thread-safe. Unfortunately, synchronization has a big negative impact on performance, even when using these collections from a single thread.



It is better to use their new unsynchronized replacements:

  • ArrayList or LinkedList instead of Vector

  • Deque instead of Stack

  • HashMap instead of Hashtable

  • StringBuilder instead of StringBuffer



总结

当我们需要频率变更字符串的时候,请使用StringBuilder,效率更高。

代码就是最好的解释,我们在学习开发过程中,要培养自己阅读英文的能力,上面的英文都比较容易理解,是很好的入门学习材料。



发布于: 2020 年 12 月 21 日阅读数: 13
用户头像

HQ数字卡

关注

还未添加个人签名 2019.09.29 加入

略懂后端的RD

评论

发布
暂无评论
【Java入门】String,StringBuffer和StringBuilder