• 深刻理解Java中的String、StringBuffer和StringBuilder的差别


          声明:本博客为原创博客,未经同意。不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(链接为http://blog.csdn.net/bettarwang/article/details/26412497),看代码和提问、讨论都更方便。

    首先简单地来梳理一下Java中String、StringBuffer和StringBuilder各自的含义。

    1.String类

        首先。它是线程安全的,即能够用于多线程编程中。

        其次,String类的对象是不可变的,即在定义时就确定了,类似String str="Hello";str+="Java";的语句事实上是生成了新的对象,仅仅是我们未察觉到而已。可是注意在大量的字符串新建对象时消耗就非常可观。这时必须考虑採用StringBuffer或StringBuilder,否则会极大地减少程序的效率。

    2.StringBuffer类:

          首先,它也是线程安全的。

          其次,它是可变类,对它指向的字符串的操作都不会产生新的对象。 每一个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自己主动添加容量。因而它的效率要比String高。 

           StringBuffer 类最经常使用的两个方法是 append 和 insert 方法,StringBuffer已经重载了这些方法,以接受随意类型的数据,所以小伙伴们。如果strBuffer是StringBuffer的对象。那么像strBuffer.append(3.14f);strBuffer.append(true);这种语句都是全然合法的

     3.StringBuilder类:

            首先,它不是线程安全的。即仅仅能用于单线程编程中。

             其次。它跟StringBuffer类似,即其对象也是一个可变的字符序列。可是要注意的是它以下几种构造方法:

             StringBuilder():创建一个容量为16的StringBuilder对象。

             StringBuilder(int capacity):创建一个容量为capacity的StringBuilder对象;

             StringBuilder(String s):创建一个包括s的StringBuilder对象。同一时候末尾加入16个空元素。

             StringBuilder(CharSequence cs):创建一个包括cs的StringBuilder对象,末尾附加16个空元素;  

          综上可知。在线程同步方面。String和StringBuffer是线程安全的,而StringBuilder不是线程安全的;在运行效率上,StringBuilder>StringBuffer>String,因而在须要大量的进行字符串操作的单线程场合,应该昼使用StringBuilder以提高效率,在大量进行字符串操作的多线程情形,StringBuffer无疑是最佳的选择。而对于少量的字符串操作的单线程或多线程情形下,使用String则更为简单、方便。

         上面对这三个类进行了一下梳理,但这仅仅是基础知识,根本谈不上深刻理解。取这么一个题目不是想哗众取宠。以下就開始结合我自己的一些经历谈一下自己的理解。

         我们都知道,String类的对象是不可变的。可是又考虑到Java中”一切皆引用“,以为在函数中传String引用能够实现值的改变。因而经常犯以下这种错误:

    import java.util.*;
    import java.io.*;
    
    public class StringTest
    {
       private static void treatString(String str)
       {
         if(str.contains("hello"))
         {
           str="hello java";
         }
         else
         {
           str="enjoy java";
         }
       }
    
       public static void main(String[]args)
       {
          String str1="hello world";
          String str2="study java";
          treatString(str1);
          treatString(str2);
          
          System.out.println(str1);
          System.out.println(str2);
       }
    }
       
          

    输出结果例如以下图所看到的:


          本来期望传递引用从而改变字符串str1和str2的值,可是从输出结果看字符串的值却是根本没有被改变,这是为什么呢?

         原来确实传递的也是引用。可是与一般的对象不同,treatString(String)函数并没有对str指向的对象进行改动(或者说并没有在str指向的内存地址上进行改动)。而是新建了一个String对象。可是这个新建的对象却是仅仅有形參指向它,实參并没有指向它。实际上整个过程中实參str都始终还是指向最開始那个对象。所以不难理解为什么会有这种输出结果。

        那么假设想要获得一般对象传递引用的效果该怎么办?

        非常easy,第一种方法,也是我个人比較推荐的方法,就是返回值String而不是void,即将上面的代码改动为:

    import java.util.*;
    import java.io.*;
    
    public class StringTest
    {
       //private static void treatString(String str)
        private static String treatString(String str)
       {
         if(str.contains("hello"))
         {
           str="hello java";
         }
         else
         {
           str="enjoy java";
         }
         
         return str;
       }
    
       public static void main(String[]args)
       {
          String str1="hello world";
          String str2="study java";
          str1=treatString(str1);
          str2=treatString(str2);
          
          System.out.println(str1);
          System.out.println(str2);
       }
    }
       
          
    此时输出结果例如以下图所看到的:



    显然。此时已经达到了我们预期的目的。

         到了这里,我再结合自己的还有一个经历,就是一開始对String.replace(oldChar,newChar);这个函数不熟悉。以为仅仅要调用它就能够实现str的改变(即以为直接str.replace(oldChar,newChar);就能实现str的改变),实际上要利用它的返回值才干改变str,即str=str.replace(oldChar,newChar);才是正确的做法。

          另外一种方法,当然就是利用StringBuffer和StringBuilder喽,由于它们是对象可变的嘛。

    详细样例到后面再追加。今天先写到这里吧。

    晚安啦,小伙伴们!  

  • 相关阅读:
    Redis提供的持久化机制(RDB和AOF)
    linux创建子进程--fork()方法
    数据库-锁的实践
    nginx中,$request_uri和$uri的区别
    journal size
    目的:将两个三T的硬盘做成LVM(sdc,sdd)
    安装 rbbitMQ redis mongo的三个扩展
    MySQL server has gone away
    mysql创建utf-8字符集数据库
    Linux下杀毒软件clamav的安装和使用
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6977857.html
Copyright © 2020-2023  润新知