<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ### 運行時常量池概述 Java運行時常量池中主要存放兩大類常量:字面量和符號引用。字面量比較接近于Java語言層面的常量概念,如文本字符串、聲明為final的常量值等。 而符號引用則屬于編譯原理方面的概念,包括了下面三類常量: - 類和接口的全限定名(包名+類名) - 字段的名稱和描述符 - 方法的名稱和描述符 ### 運行時常量池位置 運行時常量池在**JDK1.6及之前版本的JVM中是方法區的一部分**,而在HotSpot虛擬機中方法區放在了”永久代(Permanent Generation)”。所以運行時常量池也是在永久代的。 但是**JDK1.7及之后版本的JVM已經將運行時常量池從方法區中移了出來,在Java 堆(Heap)中開辟了一塊區域存放運行時常量池**。 **本文主要解惑String對象(即文本字符串)何時放入常量池,不涉及上述三類符號引用常量和其他非String常量值。而且本文只討論主流的HotSpot虛擬機。** ### String何時放入常量池 記住一句話:**直接使用雙引號聲明出來的String對象會直接存儲在常量池中。** ### 代碼一: ~~~ String a = "計算機軟件"; ~~~ 分析:因為計算機軟件五個字直接使用了雙引號聲明,故JVM會在運行時常量池中首先查找有沒有該字符串,有則直接返回該字符串在常量池中的引用;沒有則直接在常量池中創建該字符串,然后返回引用。**此時,該句代碼已經執行完畢,不會在java Heap(堆)中創建內容相同的字符串。該字符串只在常量池中創建了一個String對象。** ### 代碼二: ~~~ String a = new String("計算機軟件"); ~~~ 分析:該行代碼生成了兩個String對象(Stack(棧)中的對象引用不在討論范圍內):第一步,因為計算機軟件五個字直接使用了雙引號聲明,故JVM會在運行時常量池中首先查找有沒有該字符串,有則進入第二步;沒有則直接在常量池中創建該字符串,然后進入第二步。第二步:在常量池中創建了一個String對象之后,由于使用了new,JVM會在Heap(堆)中創建一個內容相同的String對象,然后返回堆中String對象的引用。**該行代碼分別在常量池和堆中生成了兩個內容相同的String對象。** ### 代碼三: ~~~ String a = "計算機" + "軟件"; ~~~ 分析:由于JVM存在編譯期優化,對于兩個直接雙引號聲明的String的+操作,JVM在編譯期會直接優化為“計算機軟件”一個字符串,故該行代碼同**代碼一**。 ### 代碼四: ~~~ String b = "計算機"; String a = b + "軟件"; ~~~ 分析:由于b是一個String變量,編譯期無法確定b的值,故不會優化為一個字符串。即使我們知道b的值,但JVM認為它是個變量,變量的值只能在運行期才能確定,故不會優化。運行期字符串的+連接符相當于new,故該行代碼在Heap中創建了一個內容為“計算機軟件”的String對象,并返回該對象的引用。**至此,該代碼執行完畢,因為沒有直接雙引號聲明計算機軟件這5個字的字符串,故常量池中不會生成計算機軟件這5個字的字符串。但是會有“計算機”和“軟件”這兩個String對象,因為他們都用雙引號聲明了。** ### 代碼五: ~~~ String final b = "計算機"; String a = b + "軟件"; ~~~ 分析:該代碼與代碼四的唯一區別是將b聲明為final類型,即為常量。故在編譯期JVM能確定b的值,所以對+可以優化為“計算機軟件”5個字的字符串。該代碼的運行同**代碼三和代碼一**。 ### 代碼六: ~~~ String a = new String("計算機") + "軟件"; ~~~ 分析:因為有new,該代碼也無法編譯期優化,故該行代碼只是在Heap中生成了“計算機軟件”字符串的String對象,在常量池中沒有內容相同的對象生成。 ### String.intern方法 ### 概述 String.intern()是一個Native方法,它的作用是:如果運行時常量池中已經包含一個等于此String對象內容的字符串,則返回常量池中該字符串的引用;如果沒有,則在常量池中創建與此String內容相同的字符串,并返回常量池中創建的字符串的引用。 ### JDK1.7改變 當常量池中沒有該字符串時,JDK7的intern()方法的實現不再是在常量池中創建與此String內容相同的字符串,而改為**在常量池中記錄Java Heap中首次出現的該字符串的引用,并返回該引用**。 **驗證代碼:** ~~~ String str1 = new StringBuilder("計算機").append("軟件").toString(); System.out.println((str1.intern() == str1)); //JDK1.6:false //JDK1.7:true ~~~ 或 ~~~ String b = "計算機"; String a = b + "軟件"; System.out.println(a.intern() == a); //JDK1.6:false //JDK1.7:true ~~~ ### 測試代碼 請運行以下的代碼看看你分析的結果和真正的運行結果是否一樣,JDK1.6和1.7都要跑一遍,如果你都分析對了,那就是理解了。 ~~~ //一次放開一個多行注釋運行 /* String s = new String("1"); s.intern(); String s2 = "1"; System.out.println(s == s2); String s3 = new String("1") + new String("1"); s3.intern(); String s4 = "11"; System.out.println(s3 == s4); */ /* String s = new String("1"); String s2 = "1"; s.intern(); System.out.println(s == s2); String s3 = new String("1") + new String("1"); String s4 = "11"; s3.intern(); System.out.println(s3 == s4); */ /* //+連接但編譯器不優化 String s1=new String("xy") + "z"; String s2=s1.intern(); System.out.println( s1==s1.intern() ); System.out.println( s1+" "+s2 ); System.out.println( s2==s1.intern() ); */ /*// 一般情況 String s1=new String("xyz") ; String s2=s1.intern(); System.out.println( s1==s1.intern() ); System.out.println( s1+" "+s2 ); System.out.println( s2==s1.intern() ); */ /*//編譯器優化 String s1 = "xy" + "z"; String s2 = s1.intern(); System.out.println( s1==s1.intern() ); System.out.println( s1+" "+s2 ); System.out.println( s2==s1.intern() ); */ ~~~ 說明:本文有部分內容摘抄了周志明大神的《深入理解Java虛擬機》一書,部分代碼參考了網上多個博客的內容,僅用于學習。無意侵犯版權。 參考: 《深入理解Java虛擬機-JVM高級特性與最佳實踐》周志明著 [ JVM常量池和八種基本數據及字符串](http://blog.csdn.net/rainnnbow/article/details/47018241) [深入解析String#intern](http://www.importnew.com/14142.html) [Java永久代去哪兒了](http://www.infoq.com/cn/articles/Java-PERMGEN-Removed)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看