在网上复习 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(), "/nIt'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,欢…