String与StringBuffer效率对比

昨天申请了一个LeetCode的账号,先刷了一题最基础的,字符串逆序输出。

我先写出了如下代码:

public class Solution {
    public String reverseString(String s) {
        String rev = "";
        for(int i = s.length()-1; i >= 0; i--){
            rev += s.charAt(i);
        }
        return rev;
    }
}

这份代码在OJ上运行的结果是Time Limit Exceeded,也就是超时了,显然效率太低。

我又改成如下代码,把String类换成StringBuffer类:

public class Solution {
    public String reverseString(String s) {
        StringBuffer rev = new StringBuffer();
        for(int i = s.length()-1; i >= 0; i--){
            rev.append(s.charAt(i));
        }
        return rev.toString();
    }
}

这份代码可以通过,并且用时只有6ms。

为什么String类和StringBuffer类的效率会相差这么多呢?我上网查了资料,主要是以下原因。

 

String类的对象其实是一个常量,例如String s = "abc"; 那么s其实是一个常量,它的值就是"abc",不能改变。

Java所提供的String操作方法,比如直接进行 '+' 运算,其实是作了封装,给了使用者能对String对象进行增加或删除的错觉,本质上并不是如此。

当我们执行 s += "def"; 时,并不是说 s 的内容直接由"abc"变为了"abcdef","abc"仍是"abc","def"会被暂时存储到一块新的内存里,然后再开辟一个新的内存空间,把"abc"和"def"拷贝到这个内存空间,然后 s 指向这个新的内存空间。

这个过程其实就是new了一个新的String对象,新对象是"abcdef",s 抛弃了原来的对象,指向了新对象。

由于每次操作都要重新new一个对象,并且占用大量内存,因此String类的效率不高。

 

那么StringBuffer呢?

 

StringBuffer对象是一个长度可变的对象,当对StringBuffer的进行增加或删除时,不需要new一个对象,可以动态地修改堆内存。

StringBuffer提供了append方法,在字符串的末尾进行添加。实际上,String类进行 '+' 运算,就是创建了一个StringBuffer对象,然后调用append进行添加,最后调用toString把StringBuffer转化为String。

显然,String的效率绝对不如StringBuffer了。

 

可以再看一个直观的测试样例:

    public static void main(String[] args){
        String toappend = "abcdefghijklmnopqrstuvwxyz";//26个字母,用于每次添加
        int times = 20000;//添加20000次
        //使用String类,将26个字母添加20000次
        long start = System.currentTimeMillis();
        String str = "";
        for(int i = 0; i < times; i++){
            str += toappend;
        }
        long end = System.currentTimeMillis();
        System.out.println("String time = " + (end-start)+" ms");
        
     //使用StringBuffer类,将26个字母添加20000次 start
= System.currentTimeMillis(); StringBuffer strbuf = new StringBuffer(); for(int i = 0; i < times; i++){ strbuf.append(toappend); } end = System.currentTimeMillis(); System.out.println("StringBuffer time = " + (end-start)+" ms"); }

运行结果: 

posted on 2016-05-16 09:09  木道  阅读(4534)  评论(0编辑  收藏

导航