自己動手實現Java中的StringBuffer類

Wizey發表於2019-02-26

在網上覆習 Java 的基礎知識,看到 String 和 StringBuffer 這裡,簡單的實現了下 StringBuffer 這個類,並對 String,StringBuffer,MyStringBuffer(自己實現的 StringBuffer 類名)做了拼接字串的效能測試。

String 和 StringBuffer 內部都是通過字元陣列實現的,但是 String 內部的字元陣列是在第一次賦值時就固定了長度的,不可再更改,而 StringBuffer 內部的字元陣列是留有冗餘長度的,如果超過初始容量,就動態的增大陣列的容量,使其看起來像是一個變長的陣列。

在進行大量的字串拼接時,強烈推薦使用 StringBuffer 而不是 String,因為 String 拼接字串,沒拼接一次都需要建立一個 String 物件來存放要拼接的字串。而 StringBuffer 拼接字串只是在原有字串物件的基礎上擴充套件字元陣列的空間,並不會建立新的 StringBuffer 物件,這點也是 StringBuffer 比 String 速度快的原因。

下面就來簡單實現一下 StringBuffer,取名為 MyStringBuffer。

public class MyStringBuffer{
	private int capacity = 16; // 初始容量
	private int length = 0; // 字面值字串的長度
	private char[] value;
	
	public MyStringBuffer() {
		value = new char[capacity];
	}
	
	public MyStringBuffer(String str) {
		if(str == null) {
			return;
		}
		length = str.length();
		// str字串的長度大於初始容量
		if(capacity < length) {
			capacity += length;
			value = new char[capacity];
			System.arraycopy(str.toCharArray(), 0, value, 0, length);
		} else {
			value = new char[capacity];
			System.arraycopy(str.toCharArray(), 0, value, 0, length);
		}
	}
	
	public void append(String str) {
		insert(length, str);
	}

	public void append(char c) {
		insert(length, String.valueOf(c));
	}

	public void insert(int pos, String str) {
		if(pos < 0 || pos > length || str == null) {
			return;
		}
		// 容量不夠
		while((length + str.length()) > capacity) {
			capacity += length + str.length();
			char[] newValue = new char[capacity];
			System.arraycopy(value, 0, newValue, 0, length);
			value = newValue;
		}
		char[] temp = str.toCharArray();
		// 先移後插
		System.arraycopy(value, pos, value, pos + temp.length, length - pos);
		System.arraycopy(temp, 0, value, pos, temp.length);
		length += temp.length;
	}

	public void insert(int pos, char c) {
		insert(pos, String.valueOf(c));
	}

	public void delete(int start) {
		delete(start, length - 1);
	}

	public void delete(int start, int end) {
		if(start < 0 || start > length || end < 0 || end > (length - 1) || start > length) {
			return;
		}
		System.arraycopy(value, end, value, start, length - end);
		length -= (end - start);
	}

	public void reverse() {
		// 方法一 間接法
		/*char[] temp = new char[value.length];
		for(int i = 0, j = length; i < length; i++, j--) {
			temp[i] = value[j - 1];
		}
		value = temp;*/
		// 方法二 直接法
		for(int i = 0; i < length / 2; i++) {
			char temp = value[i];
			value[i] = value[length - i - 1];
			value[length - i - 1] = temp;
		}
	}

	public int length() {
		return length;
	}
	
	public String toString() {
		char[] realValue = new char[length];
		System.arraycopy(value, 0, realValue, 0, length);
		return new String(realValue);
	}

	public int capacity() {
		return capacity;
	}
}
複製程式碼

下面是 MyStringBuffer 的測試類 MyStringBufferTest。

package com.wenshixin.character;

import org.junit.Test;

public class MyStringBufferTest {
	final int TIMES = 1000000; // 迴圈次數
	final double DIVISOR = 1000000.0; // 除數
	
	@Test
	public void constructorTest() {
		MyStringBuffer myStringBuffer = new MyStringBuffer("Weizhiwen");
		System.out.println(myStringBuffer);
		MyStringBuffer longStringBuffer = new MyStringBuffer("It`s a long road, the only key.");
		System.out.println(longStringBuffer);
	}
	
	@Test
	public void lengthAndCapacityTest() {
		MyStringBuffer myStringBuffer = new MyStringBuffer("Weizhiwen");
		System.out.println("length:"+myStringBuffer.length());
		System.out.println("capacity:"+myStringBuffer.capacity());
		MyStringBuffer longStringBuffer = new MyStringBuffer("It`s a long road, the only key.");
		System.out.println("length:" + longStringBuffer.length());
		System.out.println("capacity:" + longStringBuffer.capacity());
	}
	
	@Test
	public void reverseTest() {
		MyStringBuffer myStringBuffer = new MyStringBuffer("Weizhiwen");
		myStringBuffer.reverse();
		System.out.println(myStringBuffer);
	}
	
	@Test
	public void insertTest() {
		MyStringBuffer myStringBuffer = new MyStringBuffer("Weiwen");
		myStringBuffer.insert(3, "zhi");
		System.out.println(myStringBuffer);
		myStringBuffer.insert(0, "I`m ");
		System.out.println(myStringBuffer);
		myStringBuffer.insert(myStringBuffer.length(), "!");
		System.out.println(myStringBuffer);
		myStringBuffer.insert(myStringBuffer.length(), "
It`s a long road, the only key.");
		System.out.println(myStringBuffer);
		myStringBuffer.insert(-1, "nothing");
		System.out.println("低於下限位置插入值,顯示:" + myStringBuffer);
		myStringBuffer.insert(myStringBuffer.length() + 2, "nothing");
		System.out.println("高於上限位置插入值,顯示:" + myStringBuffer);
	}
	
	@Test
	public void appendTest() {
		MyStringBuffer myStringBuffer = new MyStringBuffer();
		myStringBuffer.append("I`m Weizhiwen");
		System.out.println(myStringBuffer);
		myStringBuffer.append("!");
		System.out.println(myStringBuffer);
	}
	
	@Test
	public void deleteTest() {
		MyStringBuffer myStringBuffer = new MyStringBuffer("I`m not Weizhiwen!");
		myStringBuffer.delete(3, 7);
		System.out.println(myStringBuffer);
	}
	
	@Test
	public void stringPerformenceTest() {
		String string = "1";
		Long startTime = System.currentTimeMillis();
		System.out.println(startTime);
		for(int i = 0; i < TIMES; i++) {
			string += "0";
		}
		Long endTime = System.currentTimeMillis();
		System.out.println(endTime);
		double avgTime = (endTime - startTime) / DIVISOR; 
		System.out.println("String平均一次的拼接時間為:" + avgTime + "毫秒。");
	}
	
	@Test
	public void stringBufferPerformenceTest() {
		StringBuffer stringBuffer = new StringBuffer("1");
		Long startTime = System.currentTimeMillis();
		System.out.println(startTime);
		for(int i = 0; i < TIMES; i++) {
			stringBuffer.append("0");
		}
		Long endTime = System.currentTimeMillis();
		System.out.println(endTime);
		double avgTime = (endTime - startTime) / DIVISOR; 
		System.out.println("StringBuffer平均一次的拼接時間為:" + avgTime + "毫秒。");
	}
	
	@Test
	public void myStringBufferPerformence() {
		MyStringBuffer myStringBuffer = new MyStringBuffer("1");
		Long startTime = System.currentTimeMillis();
		System.out.println(startTime);
		for(int i = 0; i < TIMES; i++) {
			myStringBuffer.append("0");
		}
		Long endTime = System.currentTimeMillis();
		System.out.println(endTime);
		double avgTime = (endTime - startTime) / DIVISOR; 
		System.out.println("MyStringBuffer平均一次的拼接時間為:" + avgTime + "毫秒。");
	}
}
複製程式碼

我分別做了迴圈 1000 次,10,000 次,100,000 次,1000,000 次拼接,結果是平均拼接時間 t(StringBuffer) < t(MyStringBuffer) < t(String)。

通過自己實現 StringBuffer,加深了對 StringBuffer 和 String 者兩個類的理解,Java 基礎還需加強。

個人 GitHub 地址:github.com/weizhiwen,歡…

相關文章