说明:该文档系浙江大学java应用技术第一次作业。作业内容阅读String、StringBuffer与StringBuilder类的源程序,分析比较三个类的结构、功能设置、相同与不同。
http://10.214.47.99:8080/masm/Koders/lang/String.htm
http://10.214.47.99:8080/masm/Koders/lang/StringBuffer.htm
http://10.214.47.99:8080/masm/Koders/lang/StringBuilder.htm
public final class String implements Serializable, Comparable, CharSequence
public final class StringBuffer implements Serializable, CharSequence
public final class StringBuilder
关键字final意味着String,StringBuffer, StringBulider不可被继承
####2. String成员函数返回值特点:new
String通过char[]来保存字符串,并且类成员函数的操作大都会把结果放到新开辟的一块内存然后返回一个新的字符串对象。String的操作不会改变原有的字符串。
public String concat(String str)
{
if (str.count == 0)
return this;
if (count == 0)
return str;
char[] newStr = new char[count + str.count];
VMSystem.arraycopy(value, offset, newStr, 0, count);
VMSystem.arraycopy(str.value, str.offset, newStr, count, str.count);
// Package constructor avoids an array copy.
return new String(newStr, 0, newStr.length, true);
}
public String toLowerCase(Locale loc)
{
// First, see if the current string is already lower case.
boolean turkish = "tr".equals(loc.getLanguage());
int i = count;
int x = offset - 1;
while (--i >= 0)
{
char ch = value[++x];
if ((turkish && ch == '\u0049')
|| ch != Character.toLowerCase(ch))
break;
}
if (i < 0)
return this;
// Now we perform the conversion. Fortunately, there are no multi-character
// lowercase expansions in Unicode 3.0.0.
char[] newStr = (char[]) value.clone();
do
{
char ch = value[x];
// Hardcoded special case.
newStr[x++] = (turkish && ch == '\u0049') ? '\u0131'
: Character.toLowerCase(ch);
}
while (--i >= 0);
// Package constructor avoids an array copy.
return new String(newStr, offset, count, true);
}
public char[] toCharArray()
{
// XXX ORP 1.0.9 crashes on (char[]) clone() during bootstrap, so we
// omit this optimization for now.
// if (count == value.length)
// return (char[]) value.clone();
char[] copy = new char[count];
VMSystem.arraycopy(value, offset, copy, 0, count);
return copy;
}
值得一提的是:对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象
####3. StringBuffer和StringBuilder直接在原字符串上进行操作
我做了一个小测试供读者直观感受
public class test {
public static void main(String []args) {
StringBuffer s = new StringBuffer("123");
s.replace(1,2,"ABC");
String a = new String("123");
a.replace("A","ABC");
StringBuilder b = new StringBuilder("123");
b.replace(1,2,"ABC");
System.out.println(s); // out: 1ABC3
System.out.println(a); // out: 123
System.out.println(b); // out: 1ABC3
}
}
其实我们对比一下三个类的replace源码就能很直观的看出来
/*String*/
public String replace(char oldChar, char newChar)
{
if (oldChar == newChar)
return this;
int i = count;
int x = offset - 1;
while (--i >= 0)
if (value[++x] == oldChar)
break;
if (i < 0)
return this;
char[] newStr = (char[]) value.clone();
newStr[x] = newChar;
while (--i >= 0)
if (value[++x] == oldChar)
newStr[x] = newChar;
// Package constructor avoids an array copy.
return new String(newStr, offset, count, true);
}
/*StringBuffer*/
public synchronized StringBuffer replace(int start, int end, String str)
{
if (start < 0 || start > count || start > end)
throw new StringIndexOutOfBoundsException(start);
int len = str.count;
// Calculate the difference in 'count' after the replace.
int delta = len - (end > count ? count : end) + start;
ensureCapacity_unsynchronized(count + delta);
if (delta != 0 && end < count)
VMSystem.arraycopy(value, end, value, end + delta, count - end);
str.getChars(0, len, value, start);
count += delta;
return this;
}
/*StringBuilder*/
public StringBuilder replace(int start, int end, String str)
{
if (start < 0 || start > count || start > end)
throw new StringIndexOutOfBoundsException(start);
int len = str.count;
// Calculate the difference in 'count' after the replace.
int delta = len - (end > count ? count : end) + start;
ensureCapacity(count + delta);
if (delta != 0 && end < count)
System.arraycopy(value, end, value, end + delta, count - end);
str.getChars(0, len, value, start);
count += delta;
return this;
}
由于String对象每次操作都是返回一个新的字符串,我们可以想象在一个程序中假如存在大量的String对象,或者更形象点有个10000次的循环中有着String对象的操作,这些操作会产生大量冗余的内存,不利于程序的性能。
不过需要指出的是,在一些特殊情况下例如字符串常量的拼接,String对象比StringBuffer和StringBuilder更有速度的上的优势,例如
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer S2 = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
S1的速度要比S2快。原因是在JVM看来 String S1 = “This is only a” + “ simple” + “test”; 其实就是:String S1 = “This is only a simple test”;而S2的构建则设计几个对象的构造,自然会慢一些。
####4. StringBuffer的特点关键字**“synchronized”:
阅读StringBuffer的源码不难发现很多成员前都有”synchronized"的关键字,这也意味着StringBuffer是线程安全**的
public synchronized StringBuffer append(char ch)
{
ensureCapacity_unsynchronized(count + 1);
value[count++] = ch;
return this;
}
public synchronized StringBuffer append(char[] data, int offset, int count)
{
if (offset < 0 || count < 0 || offset > data.length - count)
throw new StringIndexOutOfBoundsException();
ensureCapacity_unsynchronized(this.count + count);
VMSystem.arraycopy(data, offset, value, this.count, count);
this.count += count;
return this;
}
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
理解:
插语:我也不懂什么是线程安全什么是线程不安全,这学期才开始学操作系统。网上学习了下,大致是这个意思:
- 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
所以说StringBuffer有’'synchronized"修饰,所以是线程安全的,StringBuilder则是线程不安全的。
####5.StringBuilder线程不安全
StringBuilder和StringBuffer功能上差不多,但是StringBuilder没有关键字”synchronized"修饰,也就意味着StringBuilder是线程不安全的。
在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低。
——http://www.cnblogs.com/myhappylife/p/6542633.html
该测试来自海子博主的博客,感谢海子这篇深入浅出的文章。但是里面反编译这块的知识我还是看不懂,甚是遗憾。
博客链接为:http://www.cnblogs.com/dolphin0520/p/3778589.html
博主Mac2016, IntelliJ IDEA的测试结果为:
测试代码如下:
public class Main {
private static int time = 50000;
public static void main(String[] args) {
testString();
testStringBuffer();
testStringBuilder();
test1String();
test2String();
}
public static void testString () {
String s="";
long begin = System.currentTimeMillis();
for(int i=0; i
上面提到过,string += "hello"会被JVM自动优化为
StringBuilder str = new StringBuilder(string);
str.append(“hello”);
str.toString();
海子博主给了测试代码,博主Mac2016, IntelliJ IDEA的测试结果为:
和海子博主在win7上的测试结果有点差别,我也不知道是为什么, 被自己菜哭了(╥╯^╰╥)。海子博主的结果为:
测试代码:
public class Main {
private static int time = 50000;
public static void main(String[] args) {
testString();
testOptimalString();
}
public static void testString () {
String s="";
long begin = System.currentTimeMillis();
for(int i=0; i
http://www.cnblogs.com/dolphin0520/p/3778589.html
http://blog.csdn.net/ghevinn/article/details/37764791
http://blog.csdn.net/rmn190/article/details/1492013
http://www.cnblogs.com/myhappylife/p/6542633.html
浙江大学楼学庆老师提供的的String,StringBuffer,StringBuilder的源码
感谢大佬们的分享,收益良多(~ ̄▽ ̄)~