String、StringBuffer、StringBuilder 性能测试
2016-07-20 21:01
489 查看
这几个时常用于比较,我们通过实验来分析其性能,然后试图去寻找背后的原因。
实验总的代码:
具体分析:
1、执行(1)所花时间最长,是其他的上万倍,可见其性能不大好哇。
原因分析:我们可以通过一次小实验来分析其原因。
从上面可知,str3 与 str4 其实是两个不同的对象(String 重写了hashcode() 和 equals() 方法,所以 输出的hashcode必然是一样的)。所以,也就是说,每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象。所以,当不断循环时,之前的 string对象将不在被引用,会触发JVM的GC,所以速度慢。
2、执行(2)的时候,从代码 str.append(“append-“); 也可以看出 ,是在原来对象的做值的修改,而且是县城安全的:
3、执行(3)中的时候,与(2)中几乎无差异,只是它不是线程安全的,所以稍微快点:
4、执行(4)中所花的时间几乎就是for() 所花费的时间,应为 newStr只要执行一次 就可以了。
5、执行(5)时,每次都要去str所指向的地址找到相应的值,然后做拼接,所以花费的时间是(4)的数倍。
结论:
1、性能方面:
StringBuilder >(略大于) StringBuffer >>(远大于) String;
2、StringBuffer 是线程安全的、可变;
3、经常改变内容的字符串最好不用 String 类型。
实验总的代码:
public class Test { final static int NUM = 100000; public static void testString(String str){ long start = System.currentTimeMillis(); for(int i=0; i<NUM; i++){ str += "append-"; } long end = System.currentTimeMillis(); System.out.println(str.getClass().getName() + " 共占用了 : "+ (end-start) + " 毫秒"); } public static void testString(StringBuffer str){ long start = System.currentTimeMillis(); for(int i=0; i<NUM; i++){ str.append("append-") ; } long end = System.currentTimeMillis(); System.out.println(str.getClass().getName() + " 共占用了 : "+ (end-start) + " 毫秒"); } public static void testString(StringBuilder str){ long start = System.currentTimeMillis(); for(int i=0; i<NUM; i++){ str.append("append-"); } long end = System.currentTimeMillis(); System.out.println(str.getClass().getName() + " 共占用了 : "+ (end-start) + " 毫秒"); } //字符串對象引用相加 public static void testStringAppend(){ String str = "abc"; long start = System.currentTimeMillis(); for(int i=0; i<NUM; i++){ String newStr = str+ str+ str; } long end = System.currentTimeMillis(); System.out.println("字符串对象引用相加类型使用的时间为: " + " 共占用了 : "+ (end-start) + " 毫秒"); } //字符串直接相加 public static void testStringAdd(){ long start = System.currentTimeMillis(); for(int i=0; i<NUM; i++){ String newStr = "abc"+ "abc" + "abc"; } long end = System.currentTimeMillis(); System.out.println("字符串相加: " + " 共占用了 : "+ (end-start) + " 毫秒"); } public static void main(String[] args) { String s= "asdf"; StringBuffer sbf = new StringBuffer("asdf"); StringBuilder sbd = new StringBuilder("asdf"); Test.testString(s); (1) Test.testString(sbf); (2) Test.testString(sbd); (3) Test.testStringAdd(); (4) Test.testStringAppend(); (5) } } 结果: java.lang.String 共占用了 : 26996 毫秒 java.lang.StringBuffer 共占用了 : 6 毫秒 java.lang.StringBuilder 共占用了 : 4 毫秒 字符串相加: 共占用了 : 1 毫秒 字符串对象引用相加类型使用的时间为: 共占用了 : 13 毫秒
具体分析:
1、执行(1)所花时间最长,是其他的上万倍,可见其性能不大好哇。
原因分析:我们可以通过一次小实验来分析其原因。
public class TestSmaller { public static void main(String[] args) { String str1 = "append-"; String str2 = "asdf-"; String str3 = "append-"+"asdf-" ; String str4 = str1 + str2; System.out.println(str4.equals(str3) +" 其內容是: "+ str3); System.out.println(str3 == str4); System.out.println(str3.hashCode()); System.out.println(str4.hashCode()); } } 输出结果: true 其內容是: append-asdf- false 210131462 210131462
从上面可知,str3 与 str4 其实是两个不同的对象(String 重写了hashcode() 和 equals() 方法,所以 输出的hashcode必然是一样的)。所以,也就是说,每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象。所以,当不断循环时,之前的 string对象将不在被引用,会触发JVM的GC,所以速度慢。
2、执行(2)的时候,从代码 str.append(“append-“); 也可以看出 ,是在原来对象的做值的修改,而且是县城安全的:
public synchronized StringBuffer append(String str) { super.append(str); return this; } 而super.append(str); 指的是基类中 public AbstractStringBuilder append(String str) { if (str == null) str = "null"; int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; }
3、执行(3)中的时候,与(2)中几乎无差异,只是它不是线程安全的,所以稍微快点:
public StringBuilder append(String str) { super.append(str); return this; }
4、执行(4)中所花的时间几乎就是for() 所花费的时间,应为 newStr只要执行一次 就可以了。
5、执行(5)时,每次都要去str所指向的地址找到相应的值,然后做拼接,所以花费的时间是(4)的数倍。
结论:
1、性能方面:
StringBuilder >(略大于) StringBuffer >>(远大于) String;
2、StringBuffer 是线程安全的、可变;
3、经常改变内容的字符串最好不用 String 类型。
相关文章推荐
- java递归简单实例
- java枚举使用
- Java笔记01-Java开发基础
- 广师Android群分享之Java SE知识
- 一天一个数据结构之ArrayList
- Java基础知识整理(一)
- java 复用类
- hashCode与equals的作用与区别及应当注意的细节
- java-数值类型之间的转换
- PO、VO、DTO、POJO以及JavaBean介绍
- java语言-基础(Windows 命令行常用命令)
- 构造代码块、equals
- 【转载】java中重载与重写的区别
- 7.Java运算符
- 10.Java命名空间
- java中的运算符!!绝对经典!值得收藏!!
- POJ 2259 Team Queue(队列)
- 【一天一道LeetCode】#225. Implement Stack using Queues
- 【一天一道LeetCode】#225. Implement Stack using Queues
- UIScrollView 几乎所有的属性和方法