<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>

          Java專欄:字符串常量池、String詳解

          共 3816字,需瀏覽 8分鐘

           ·

          2022-09-29 17:59

          關(guān)注Java學(xué)習(xí)之道一起成長,一起學(xué)習(xí)~

          作者: 遠(yuǎn)赴山河萬里
          來源: blog.csdn.net/weixin_43615816/article/details/122882249

          Part1String Pool

          String 的字符串常量池(String Pool)是一個(gè)固定大小的 HashTable(數(shù)組+鏈表的數(shù)據(jù)結(jié)構(gòu)),故不存在兩個(gè)相同的字符串。也叫 StringTableStringTable是放在本地內(nèi)存的,是C++寫的,里面放的是字符串對(duì)象的引用,真實(shí)的字符串對(duì)象是在堆里。

          1.1字符串常量池產(chǎn)生時(shí)間

          像這些靜態(tài)的、未加載的.class文件的數(shù)據(jù)被稱為靜態(tài)常量池,但經(jīng)過jvm把.class文件裝入內(nèi)存、加載到方法區(qū)后,常量池就會(huì)變?yōu)檫\(yùn)行時(shí)常量池。當(dāng)類加載到內(nèi)存中后,jvm就會(huì)將class常量池中的內(nèi)容存放到運(yùn)行時(shí)常量池中,運(yùn)行時(shí)常量池存在于內(nèi)存中,也就是class常量池被加載到內(nèi)存之后的版本。

          不同之處是:它的字面量可以動(dòng)態(tài)的添加(String#intern()),符號(hào)引用可以被解析為直接引用。

          簡單來說,HotSpot VM里StringTable是個(gè)哈希表,里面存的是駐留字符串的引用(而不是駐留字符串實(shí)例自身)。也就是說某些普通的字符串實(shí)例被這個(gè)StringTable引用之后就等同被賦予了“駐留字符串”的身份。這個(gè)StringTable在每個(gè)HotSpot VM的實(shí)例里只有一份,被所有的類共享。類的運(yùn)行時(shí)常量池里的CONSTANT_String類型的常量,經(jīng)過解析(resolve)之后,同樣存的是字符串的引用;解析的過程會(huì)去查詢StringTable,以保證運(yùn)行時(shí)常量池所引用的字符串與StringTable所引用的是一致的。

          字符串常量池
          本質(zhì)就是一個(gè)哈希表
          存儲(chǔ)的是字符串實(shí)例的引用
          在被整個(gè)JVM共享
          在解析運(yùn)行時(shí)常量池中的符號(hào)引用時(shí),會(huì)去查詢字符串常量池,確保運(yùn)行時(shí)常量池中解析后的直接引用跟字符串常量池中的引用是一致的

          1.2字符串常量池的位置

          以下圖表示的是運(yùn)行時(shí)數(shù)據(jù)區(qū)

          1.3字符串常量池的優(yōu)點(diǎn)

          為了避免頻繁的創(chuàng)建和銷毀對(duì)象而影響系統(tǒng)性能,實(shí)現(xiàn)了對(duì)象的共享。 例如字符串常量池,在編譯階段就把所有的字符串文字放到一個(gè)常量池中。 節(jié)省內(nèi)存空間:常量池中所有相同的字符串常量被合并,只占用一個(gè)空間。 節(jié)省運(yùn)行時(shí)間:比較字符串時(shí),==比equals()快。對(duì)于兩個(gè)引用變量,只用==判斷引用是否相等,也就可以判斷實(shí)際值是否相等。

          歡迎關(guān)注公眾號(hào)"Java學(xué)習(xí)之道",查看更多干貨!

          Part2String

          2.1不可變性

          public final class String
              implements java.io.SerializableComparable<String>, CharSequence 
          {
              /** The value is used for character storage. */
              private final char value[];
          }

          2.2定義方式

          字面量的方式

          String s1 = "hello";

          此時(shí)會(huì)有如下過程。 會(huì)去解析的符號(hào)引用,ldc指令,會(huì)先到字符串常量池中查找是否存在對(duì)應(yīng)字符串實(shí)例的引用,如果有的話,那么直接返回這個(gè)字符串實(shí)例的引用,如果沒有的話,會(huì)創(chuàng)建一個(gè)字符串實(shí)例,那么將其添加到字符串常量池中(實(shí)際上是將其引用放入到一個(gè)哈希表中),之后再返回這個(gè)字符串實(shí)例對(duì)象的引用。

          ldc:將int、float、或者一個(gè)類、方法類型或方法句柄的符號(hào)引用、還可能是String型常量值從常量池中推送至棧頂,在執(zhí)行l(wèi)dc指令時(shí)會(huì)觸發(fā)對(duì)它的符號(hào)引用進(jìn)行解析。

          new的方式

          問題:以下方式會(huì)創(chuàng)建幾個(gè)對(duì)象?怎么證明?

          String str = new String("hello");

          2個(gè)對(duì)象或者1個(gè)對(duì)象

          ①如果字符串常量池中已經(jīng)有“hello”,則創(chuàng)建了一個(gè)對(duì)象。如下圖。

          public class Main {
              public static void main(String[] args) {
                  String s1 = "hello";
                  String s2 = new String("hello");
                  System.out.println(s1==s2);
              }
          }
          //輸出:false,由圖容易看出

          ②如果字符串常量池中不存在“hello”,則創(chuàng)建了兩個(gè)對(duì)象。

          一個(gè)對(duì)象是:new關(guān)鍵字在堆空間創(chuàng)建的 另一個(gè)對(duì)象是:另外一個(gè)是在解析常量池的時(shí)候JVM自動(dòng)創(chuàng)建的,如下圖。

          歡迎關(guān)注公眾號(hào)"Java學(xué)習(xí)之道",查看更多干貨!

          intern()的方式

          如果不是用字面量的方式定義的String對(duì)象,可以使用String提供的intern方法:intern方法會(huì)從字符串常量池中查詢當(dāng)前字符串是否存在,若存在則返回其引用;若不存在就會(huì)將當(dāng)前字符串放入常量池中,并返回其引用。我們只需牢記返回的是字符串常量池的引用(即哈希表中的值)即可。

          public class Main {
              public static void main(String[] args) {
                  String s1 = new String("1");
                  String s2=s1.intern();
                  String s3 = "1";
                  System.out.println(s2 == s3);
              }
          }

          分析:true

          第一行,創(chuàng)建了兩個(gè)對(duì)象實(shí)例,其引用一個(gè)在字符串常量池中,一個(gè)返回給s,如上圖。

          第二行,intern()方法會(huì)會(huì)從字符串常量池中查詢當(dāng)前字符串是否存在,發(fā)現(xiàn)存在,返回的是字符串常量池的引用(地址)。

          第三行,s3是賦值為字符串常量池的引用。 故 s2和s3地址一樣。

          2.3字符串拼接

          String s =new String("1")+new String("1");

          分析:true

          執(zhí)行完成后,堆區(qū)多了兩個(gè)匿名對(duì)象,另外堆區(qū)還多了一個(gè)字面量為11的字符串實(shí)例,并且棧中存在一個(gè)引用指向這個(gè)實(shí)例。當(dāng)我們?cè)谶M(jìn)行字符串拼接時(shí),編譯器默認(rèn)會(huì)創(chuàng)建一個(gè)StringBuilder對(duì)象并調(diào)用其append方法來進(jìn)行拼接,最后再調(diào)用其toString方法來轉(zhuǎn)換成一個(gè)字符串,StringBuildertoString方法其實(shí)就是new一個(gè)字符串。

          //StringBuilder的toString方法
          @Override
          public String toString() {
              // Create a copy, don't share the array
              return new String(value, 0, count);
          }
          -- END --

           | 更多精彩文章 -



          ← 左右滑動(dòng)與Java學(xué)習(xí)之道互動(dòng)交流 →

          加我微信,交個(gè)朋友
          長按/掃碼添加↑↑↑

          瀏覽 49
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  香蕉网视频 | 做受 视频毛片下载 | 超逼视频在线观看 | 欧美精品第一页 | 婷婷激情五月天中文字幕 |