五月综合人人91天堂久久人妻|欧美成人精品H超碰超碰网站大全|在线国产三级片丁香综合无码视频|国产不卡23区www.AV在线|国产91色哟在亚洲无码强奸在线|岛国黄色视屏久久免费看黄片|91无码视频国产综合23p|日本人成在线春色激情69

衡水天泰計(jì)算機(jī)培訓(xùn)學(xué)校
JAVA技術(shù)

Java中的字符串駐留

來源:衡水北大青鳥 ????發(fā)布時(shí)間:2017-04-11 10:51 ????點(diǎn)擊:

最近在工作的時(shí)候,一句再正常不過的代碼String a = “hello” + “world”;被改成了new StringBuilder().append(“hello”).append(“world”);當(dāng)時(shí)就比較疑惑這樣做的好處,后來到網(wǎng)上查找了一番之后才清楚這與Java中的字符串駐留機(jī)制有關(guān),那么什么是駐留呢?
顧名思義,駐留就是在內(nèi)存中保留(在Java中,我們通常稱駐留對象的地方為駐留池,不過它也是內(nèi)存的一部分),它不僅存在于Java中,在C#中同樣存在。那么我就寫幾個(gè)例子來講解什么叫Java中字符串的駐留:
1
2
3
4
5
6
7
8
9
10
public class test {
  public static void main(String[] args) {
      String a = "abc";
      String b = "abc";
      System.out.println(a == b);  // true
      String c = new String("abc");
      System.out.println(a == c);  // false
      System.out.println(a.equals()); // true  
  }
}
上面這段代碼在執(zhí)行完String a = “abc”這一句的時(shí)候會(huì)在內(nèi)存中創(chuàng)建一個(gè)值為abc的String類型對象。當(dāng)執(zhí)行下一句代碼,即String b = “abc”的時(shí)候,java會(huì)首先去駐留池里面查找是否有值為abc的字符串對象,如果有就讓b引用執(zhí)行那個(gè)對象,如果沒有就新創(chuàng)建一個(gè)并且將其存放在駐留池中。所以,不難理解,當(dāng)程序執(zhí)行到第三句話的時(shí)候會(huì)返回true,我們知道==在java中比較的是對象的引用指向的對象的內(nèi)存首地址是否一樣,而a和b指向的是同一個(gè)對象,所以會(huì)返回true。繼續(xù)往下走,當(dāng)程序執(zhí)行到String c = new String(“abc”)這句話的時(shí)候,java做的事包括: 檢查abc這個(gè)字符串對象是否在駐留池中,如果存在就把它當(dāng)做值,然后再在堆上創(chuàng)建一個(gè)String類型的對象放到堆中(我們都知道在java中對象是放在堆中,對象的引用是存放在棧中)。所以這句話其實(shí)可能創(chuàng)建了2個(gè)對象(如果abc已經(jīng)在駐留池中了,就只是在堆中創(chuàng)建了一個(gè)對象)。同時(shí)通過new String()創(chuàng)建出來的字符串對象是不會(huì)被放到駐留池中的。你也許會(huì)想,有沒有一種方法讓我把在堆中創(chuàng)建的對象放到駐留池中去呢?答案是有的!java提供了一個(gè)方法叫做intern(),如果執(zhí)行c.intern(),會(huì)首先把c指向的對象放到駐留池中,然后返回指向這個(gè)對象的引用。那么,以下代碼會(huì)輸出什么呢!
1
2
3
4
5
6
7
8
public class test {
  public static void main(String[] args) {
      String a = "abc";
      String b = new String("abc");
      System.out.println(a == b.intern());  // true
      System.out.println(a == b);  // false
  }
}
當(dāng)然是true!不過它的執(zhí)行過程還是值得說一下的,重點(diǎn)在b.intern();這句話上。經(jīng)過上面的講解你也許會(huì)想過程應(yīng)該是首先到堆中創(chuàng)建一個(gè)值為abc的String對象,然后將這個(gè)對象放到駐留池中。那么如果駐留池中已經(jīng)存在值為abc的字符串對象了呢?那么b.intern會(huì)直接返回駐留池中的對象,所以這里會(huì)返回true。繼續(xù)向下執(zhí)行,System.out.println(a == b);會(huì)返回false,因?yàn)樵趫?zhí)行b.intern();這句話的時(shí)候,實(shí)際上是直接返回了駐留池中的對象,所以對原本b指向的堆中的對象沒有影響,所以a == b會(huì)返回false。
我通過上面這個(gè)例子簡單講解了java中的字符串駐留,那么現(xiàn)在回到文章開始部分的疑惑去,為什么使用StringBuilder而不是簡單地使用”+”來連接字符串呢?經(jīng)過上面的講解,你可能會(huì)猜測StringBuilder用了字符串駐留,而”+”不是。恭喜你,你答對了,加10分。但是你也許并不知道使用”+”的時(shí)候tricky的地方在哪里。繼續(xù)往下看。
原因在于使用+連接字符串每次都生成新的對象,而且是在堆內(nèi)存上進(jìn)行,而堆內(nèi)存速度比較慢(相對而言),那么再大量連接字符串時(shí)直接+是不可取的,當(dāng)然需要一種效率高的方法。Java提供的StringBuffer和StringBuilder就是解決這個(gè)問題的。區(qū)別是前者是線程安全的而后者是非線程安全的。所以促使我寫這篇博客的問題的原因就找到了。此外,值得注意的一點(diǎn)是,駐留池是不會(huì)被GC回收的,它會(huì)在程序運(yùn)行期間一直保留。
最后我還想再說點(diǎn)題外話,請看下面這段程序:
 
public class test {
  public static void main(String[] args) {
      String a = "a";
      String b = "b";
      String c = "ab";
      String d = "a" + "b";
      String e = a + "b";
      String f = a + b;
      System.out.println(c == d);  // true
      System.out.println(c == e);  // false
      System.out.println(c == f);  // false
      System.out.println(d == e);  // false
      System.out.println(d == f);  // false
      System.out.println(e == f);  // false
  }
}
c == d輸出true,因?yàn)閏和d都是字符串常量,他們的值在編譯時(shí)就確定了。而所有涉及到引用的地方都是在運(yùn)行時(shí)才確定值的,所有下面會(huì)全部輸出為false。
掃一掃 加關(guān)注 精彩資訊在這里!

技能認(rèn)證

OSTA技能證書,全國可查,真實(shí)可信

多項(xiàng)熱門專業(yè)自由選擇

豐富的專業(yè)課程設(shè)置,完全自由選擇

畢業(yè)推薦就業(yè)

5重就業(yè)保障體系,4項(xiàng)就業(yè)指導(dǎo)服務(wù)

學(xué)校地址

最方便的乘車路線

在線咨詢

來校講解答疑

在線咨詢

399入學(xué)禮包

報(bào)名熱線

0318-2888080

  • 版權(quán)所有2015~2021 衡水天泰計(jì)算機(jī)培訓(xùn)學(xué)校
    北大青鳥課程咨詢電話:0318-2888080 官方網(wǎng)址:m.076735.cn
    地址:河北省衡水市育才街與勝利交叉口南行200米路東 郵編:053000
    (網(wǎng)站客服咨詢QQ:3142643279)
  • 網(wǎng)站備案/許可證號:冀ICP備19035316號-1