zoukankan      html  css  js  c++  java
  • 三大类库(一)之字符串性能分析

    一、分析

    String类字符串追加

      当我们对字符串进行拼接时,String:是对象不是原始类型.为不可变对象,一旦被创建,就不能修改它的值.对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.String 是sealed 类,即不能被继承.

        string是String类的别名,引用类型,且该类型是只读的,不可修改,当你修改字符串内容时,实际上是创建了另一个新的字符串并将引用指向了它,你可以参考String类型的构造函数说明,就明白错在哪里了。第一条只是创建了一个String类型的数组,并未对其初始化,如果你对该数组中的任一成员使用第二条的方法进行初始化,一样会报错。

         str += "a";等效于:str = new StringBuffer(str).append("a").toString(); 虽然编译器对字符串加号做了优化,它会用StringBuffer的append方法进行追加。再是通过toString方法转换成String字符串的。 它与纯粹的append方法是不同的 

    一是每次都要创建一个StringBuilder对象 

    二是每次执行完毕都要调用toString方法将其转换为字符串 

      因此,字符串类型的字符追加有可能会消耗大量的时间,因为每次追加完成之后都要return返回一个新的字符串,每次的操作都会一个新的String对象,这就是直接使用速度慢下来的原因。 

    StringBuffer的字符串追加

         StringBuffer:是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象,它只能通过构造函数来建立,StringBuffer sb = new StringBuffer();它不能直接对其进行赋值操作,sb = "I Hava a Dream";//错误,对象被建立以后,在内存中就会分配内存空间,并初始保存一个null.向StringBuffer中赋值的时候可以通过它的append方法.sb.append("当然的");

    StringBuilder
    -> 字符串不可变,长期拼接字符串性能较低
    -> Stringbuilder
    Append(string);
    AppendLine(string);
    AppendFormat("{0}{1}{2}{3}", 1, "23", "ab", true);
    ToString();

         所以它必须通过追加的方式进行赋值。它的内部实现代码如下:

     1 public AbstractStringBuilder append(String str){ 
     2     //如果是null值,则把null作为字符串处理 
     3     if(str == null)str = "null"; 
     4  
     5     int len = str.length(); 
     6     //字符串的长度为0,则返回自身 
     7     if(len == 0)return this; 
     8  
     9     int newCount = count + len; 
    10     //追加后的字符串组长度是否超过当前值 
    11     if(newCount > value.length) 
    12         expandCapacity(newCount);//加长,并作数组拷贝 
    13     //字符串复制到目标数组 
    14     str.getChars(0, len, value, count); 
    15     count = newCount; 
    16  
    17     return this; 
    18 } 

    在StringBuffer中进行追加时不需要建立新的对象,开辟新的空间,它始终是一个对象,而String 对象是不可变对象,每次操作Sting 都会重新建立新的对象来保存新的值.
    这样原来的对象就没用了,就要被垃圾回收.这也是要影响性能的。

    二、场景模拟

          我们使用Stopwatch类分别对这两种情况进行模拟计时,在C#中有一个秒表类:stopwatch,用这个类可以方便的测试一下代码运行时间。

     1 Stopwatch sp=new Stopwatch();
     2 sp.start();
     3 string s="";
     4 for(int i=0;i<100000;i++)
     5 {
     6         s+=i.toString();
     7 }
     8 sp.Stop();
     9 Console.WriteLine(sp.Elapsed);
    10 Console.ReadKey();

    结果表明:时间花了30多秒 

    而对于StringBuilder:

     1 Stopwatch sp=new Stopwatch();
     2  sp.start();
     3  StringBuilder sb=new StringBuilder();
     4  for(int i=0;i<100000;i++)
     5  {
     6          s+=sb.Append(i.toString());
     7  }
     8  sp.Stop();
     9 Console.WriteLine(sp.Elapsed);
    10  Console.ReadKey();

    结果表明:时间花了0.几秒,相差了两个数量级

    三、结论

    当我们的系统性能不临界的时候,string类型的简答追加比较接地气,符合人们通常的写代码的习惯,而当系统性能临界,我们要进行数量级比较大的循环,我们就应该使用StringBuilder,提高我们的代码优化。

     

  • 相关阅读:
    Python 存储引擎 数据类型 主键
    Python 数据库
    Python 线程池进程池 异步回调 协程 IO模型
    Python GIL锁 死锁 递归锁 event事件 信号量
    Python 进程间通信 线程
    Python 计算机发展史 多道技术 进程 守护进程 孤儿和僵尸进程 互斥锁
    Python 异常及处理 文件上传事例 UDP socketserver模块
    Python socket 粘包问题 报头
    Django基础,Day7
    Django基础,Day6
  • 原文地址:https://www.cnblogs.com/fuGuy/p/5654576.html
Copyright © 2011-2022 走看看