<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          String、StringBuilder和StringBuffer

          共 5212字,需瀏覽 11分鐘

           ·

          2021-05-14 12:28

          點擊上方藍色字體,選擇“標星公眾號”

          優(yōu)質文章,第一時間送達

            作者 |  H-utopia

          來源 |  urlify.cn/yArQje

          【String】

          首先,從String類的定義入手,可以看到String類是由final修飾,即不可變的,一旦創(chuàng)建出來就不可修改,因此首先明確,字符串的拼接、截取等操作都會產(chǎn)生新的字符串對象。

           

          觀察以下幾種創(chuàng)建Stirng的語句

          1 String s1 = "hello ";
          2 String s2 = "world";
          3 String s3 = s1 + s2;
          4 String s4 = "hello " + "world";
          5 String s5 = new String("hello world");

          1> 對于s1,直接通過字符串常量創(chuàng)建,會先查找常量池中是否有 hello 這個字符串,有的話不創(chuàng)建,沒有的話新建,因此會在常量池中創(chuàng)建一個對象。

          2> 對于s2,同上,在常量池中創(chuàng)建一個對象。

          3> 對于s3,字符串拼接操作,查看反匯編代碼,字符串拼接實際上是new StringBuilder(),然后執(zhí)行其append()方法,最后執(zhí)行toString,過程中創(chuàng)建了3個對象。

          4> 對于s4,直接通過常量字符串拼接,會被優(yōu)化為創(chuàng)建 hello world,在常量池中創(chuàng)建對象。

          5> 對于s5,new操作一定會在堆中創(chuàng)建對象,然后查找常量池中是否有 hello world 這個字符串,沒有就在常量池中創(chuàng)建一個。

          對于s3、s4、s5,字符串的內容都是hello world,但對于s3和s5,引用的都是堆中創(chuàng)建的字符串對象,s4引用的則直接是常量池中的對象,因此它們三個的引用都是不同的,如下

          intern

          通過上面的驗證,知道直接通過常量定義的String對象是位于常量池中,而通過new顯式創(chuàng)建或者拼接隱式創(chuàng)建的String對象是位于堆中。

          除了常用的操作字符串方法,JDK還提供了 inter() 方法,該方法的官方說明如下,作用是當方法調用時,如果常量池中已經(jīng)包含一個和這個String相等(內容相同,即equals方法)的String,就會返回常量池中的對象,否則,這個對象會被添加到常量池,然后返回她的引用。簡單來說其作用是把字符串緩存到常量池中。

          通過幾個例子來驗證intern的作用

          【StringBuilder和StringBuffer】

          StringBuilder和StringBuffer都表示可變的字符串序列,可以通過其提供的一序列方法實現(xiàn)字符串的拼接、截取,觀察源碼會發(fā)現(xiàn)兩個類的核心代碼基本一致,二者都繼承自抽象類AbstractStringBuilder。

          • 二者的共同點是均提供了字符串的拼接、截取等操作,無需每次變動都創(chuàng)建新的對象,一次創(chuàng)建,最后只需通過toString生成最終的字符串對象即可。

          • 二者的區(qū)別在于在字符串拼接等操作上StringBuffer使用synchronized關鍵字修飾方法,多線程情況下保證了線程安全,當然相比StringBuilder,也降低了性能。

          通過源碼來看動態(tài)拼接字符串邏輯,StringBuilder和StringBuffer都是調用父類的append方法實現(xiàn),因此二者實現(xiàn)邏輯是一致的,其中count是用來記錄value數(shù)組已經(jīng)使用的長度,即在現(xiàn)有的value數(shù)組后面拼接上新的str字符串。因此在StringBuilder中,代碼中的 count+=len 不是原子操作,多線程操作的情況下,例如當前count為5,可能出現(xiàn)多個線程拿到的count都是5,分別執(zhí)行累加操作后再賦給count,得到的count只是6,此時便出現(xiàn)了線程不安全的情況。

          附:雖然上面提到,通過 + 號拼接String對象時,java也會隱式地創(chuàng)建StringBuilder對象進行拼接,通常情況下并不會造成性能效率損失,但在需要大量循環(huán)拼接字符串時,使用+拼接,會在每次循環(huán)時都創(chuàng)建一個StringBuilder對象,循環(huán)結束后,內存中會多出許多無用的StringBuilder對象,因此這種情況,建議在循環(huán)體外創(chuàng)建StringBuilder對象,循環(huán)調用其append()方法拼接,如此只需創(chuàng)建一個StringBuilder對象。

          擴容

          首先注意二者的初始容量都是16,當然也可以通過參數(shù)指定初始容量

          public StringBuilder() {
                  super(16);
              }
          public StringBuffer() {
                  super(16);
              }

          在字符串拼接時,都會調用父類AbstractStringBuilder的append方法,方法源碼如下

          public AbstractStringBuilder append(String str) {
                  if (str == null) {
                      return appendNull();
                  }
                  int len = str.length();
                  ensureCapacityInternal(count + len);
                  putStringAt(count, str);
                  count += len;
                  return this;
              }

          其中的 ensureCapacityInternal 方法,就是在拼接前進行擴容

          private void ensureCapacityInternal(int minimumCapacity) {
                  // overflow-conscious code
                  int oldCapacity = value.length >> coder;
                  if (minimumCapacity - oldCapacity > 0) {
                      value = Arrays.copyOf(value,
                              newCapacity(minimumCapacity) << coder);
                  }
              }

          其中的minimumCapacity就是擴容后的字符串長度,超過目前容量的話,調用newCapacity方法執(zhí)行擴容,可以看出每次擴容后的容量是原容量的2倍加2,如果仍不夠,就直接擴容到需要的長度。

          private int newCapacity(int minCapacity) {
                  // overflow-conscious code
                  int oldCapacity = value.length >> coder;
                  int newCapacity = (oldCapacity << 1) + 2;
                  if (newCapacity - minCapacity < 0) {
                      newCapacity = minCapacity;
                  }
                  int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
                  return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
                      ? hugeCapacity(minCapacity)
                      : newCapacity;
              }







          粉絲福利:Java從入門到入土學習路線圖

          ??????

          ??長按上方微信二維碼 2 秒


          感謝點贊支持下哈 

          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄片无码视频 | 逼综合成人免费 | 爱搞在线国产 | 五月天激情久久 | 黄视屏久久|