前一段时间一位同事的系统崩了,电脑上重要资料全部丢失,实在遗憾。鉴于此,我想把我学过的一些东西也备份一下,以防系统崩溃之痛。
学过的东西很容易淡忘,有时候碰到问题明知道是以前解决过的,但现在却忘了如何解决这同样的问题,比较苦恼,所以我经常把自己写过的项目(可重用性高的模块)备份到U盘或者google托管上面,时不时温故一下,嘿嘿。
下面是胡总讲过的一课,我把课堂笔记写下了放这里共享一下:
字符串使用性能深入测试
一、 字符串池。
Java 中 String 是以对象的形式存在的,但是它却是值传递的。当要比较两个字符串的内容的时候,我们常采用的方法是 str1.equals(str2); ,先看下面的问题:
情况一:
String str1 = “abc”;
String str2 = “abc”;
System.out.println(str1==str2);
System.out.println(str1.equals(str2));
情况二:
String str1 = new String(“abc”);
String str2 = new String(“abc”);
System.out.println(str1==str2);
System.out.println(str1.equals(str2));
两种情况运行的结果分别是:
情况一结果:
true
true
情况二结果:
false
true
为什么会出现这种情况呢?两种字符串对象的创建之间有什么不同呢?
现在来看看 String.equals(); 方法的源代码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
我们看到,它首先是进行“ = = ”比较,然后在将字符串打成原形 bytes ,逐个比较字节,得出结果。
我们可以使用 jdk bin 目录下面的 javap 工具查看以上代码运行的指令结构。
javap –c className 回车
二、 String 、 StringBuffer 和 StringBuilder 比较 àà “比较”思想的运用。
字符串是程序中最常用的一个数据类型或对象,可以用到的类有: String , StringBuffer 和 StringBuilder 。这三个之间是有一定区别的。
下面是一个简单的类 A.java 。
public class A{
public static void main(String args[]) {
String str = "abc";
str+="z";
}
}
编译正确后,在命令行输入 javap –c A ,我们可以看到其执行的过程。如下图:
可以看到,我们在进行字符串尾部添加字符串时,其实是调用了 StringBuilder 的 append() 方法。由此可见, String 连接字符串的效率是比较的低的。
StringBuilder 的 append 方法如下:
public StringBuilder append (String str) {
super .append(str);
return this ;
}
继承了父类的 append 方法,那么它的父类是什么呢?看下面,
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
现在我们知道了, StringBuilder 是一个不能被子类重写的一个类,并且继承了 AbstractStringBuilder 类,重写了父类 append() 方法。
那么 StringBuffer 又有什么特点呢?
请看它的定义:
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
… …
}
StringBuffer 的 append() 方法如下:
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
请仔细对比 StringBuilder 的 append() ,我们发现 StringBuffer 的 append() 方法加了关键字 synchronized ,所以 StringBuffer 是线程同步的,而 StringBuilder 是非线程同步的。
接下来我们来测试一下它们的处理字符串连接速度,测试代码如下:
/**
* 测试String、StringBuffer和StringBuilder
* 字符串连接速度。
* 首先介绍一下他们之间的区别:
* 1,String在实现字符串连加时,其实是调用了StringBuilder中的append方法,所以性能上远远不及StringBuilder。
* 2,StringBuffer是一种线程安全的类,它的append()方法有一个关键词sychronization。
* 3,StringBuilder是非线程安全的,它的效率稍高于StringBuffer。
* 总的来说,他们之间就是性能上的差别。
* @author 波仔
*
*/
public class StringTest {
public static void main(String args[]) throws Exception{
int count = 10000000;
//测试String
long start = System.currentTimeMillis();
testString(count);
System.out.println("String 连接花时:"+(System.currentTimeMillis()-start)+"毫秒。");
java.lang.Runtime.getRuntime().runFinalization();
Thread.sleep(1000);
//测试StringBuffer
start = System.currentTimeMillis();
testStringBuffer(count);
System.out.println("StringBuffer连接花时:"+(System.currentTimeMillis()-start)+"毫秒。");
java.lang.Runtime.getRuntime().runFinalization();
Thread.sleep(1000);
//测试StringBuilder
start = System.currentTimeMillis();
testStringBuilder(count);
System.out.println("StringBuilder连接花时:"+(System.currentTimeMillis()-start)+"毫秒。");
java.lang.Runtime.getRuntime().runFinalization();
}
/**
* 测试String对象字符串连接的速度。
* @param count 字符串连接次数
* @return 连接后的字符串对象
*/
public static String testString(int count){
// String str = new String("abc");
String str = "abc";
for(int i = 0;i
测试结果如下
这样多次运行结果都不会相差太多。由此得知 StringBuilder 和 StringBuffer 较之 String 向尾部添加字符串的效率要高很多。
小结:在测试不同类处理同一数据的效率时,我们应该有一个全面正确的测试方案,在上面的例子中我们的 count 值不能设的太小也不能太大(内存溢出),类似的,我们可以测试一下不同集合类( ArrayList , LinkedList , HashSet , HashMap 等)的查询和添加数据的速度,由此你在以后的项目中根据具体情况使用。
姓名:肖波
时间: 2009-4-12