熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

Java對String字符串對象的創建以及管理

2022-06-13   來源: Java開源技術 

  Constant Pool常量池的概念:

  在講到String的一些特殊情況時總會提到String Pool或者Constant Pool但是我想很多人都不太明白Constant Pool到底是個怎麼樣的東西運行的時候存儲在哪裡所以在這裡先說一下Constant Pool的內容

  String Pool是對應於在Constant Pool中存儲String常量的區域習慣稱為String Pool也有人稱為String Constant Pool好像沒有正式的命名

  在java編譯好的class文件中有個區域稱為Constant Pool他是一個由數組組成的表類型為cp_info constant_pool[]用來存儲程序中使用的各種常量包括Class/String/Integer等各種基本Java數據類型詳情參見The Java Virtual Machine Specification 章節

  對於Constant Pool表的基本通用結構為:

  

  cp_info { u tag; u info[]; }


  tag是一個數字用來表示存儲的常量的類型例如表示String類型表示Long類型info[]根據

  類型碼tag的不同會發生相應變化

  對於String類型表的結構為:

  

  CONSTANT_String_info { u tag; u string_index; }


  tag固定為string_index是字符串內容信息類型為:

  

  CONSTANT_Utf_info { u tag; u length; u bytes[length]; }


  tag固定為length為字符串的長度bytes[length]為字符串的內容

  (以下代碼在jdk中編譯)

  為了詳細理解Constant Pool的結構我們參看一些代碼:

  

  String s = sss; String s = sss; Systemoutprintln(s + + s);


  由於ssssss都是字符串常量在編譯期就已經創建好了存儲在class文件中

  在編譯後的class文件中會存在這個常量的對應表示:

  

   ; sss ; sss


  根據上面說的String常量結構我們分析一下

  開始的為CONSTANT_String_info結構中的tag應該是它的相對引用為CONSTANT_Utf_info的tag為對應字符串的長度 為字符串對應的編碼接著分析會發現後面的是對應sss的存儲結構

  經過上面分析我們知道了是兩個字符串的相對引用就可以修改class文件來修改打印的內容把class文件中的 E C D改成 E C D程序就會輸出sss sss而不是和原程序一樣輸出sss sss因為我們把對sss的相對引用改成了對sss的相對引用

  

  public class Test { public static void main(String[] args) { String s = sss; String s = sss; } }


  在上面程序中存在個相同的常量sss對於n個值相同的String常量在Constant Pool中只會創建一個所以在編譯好的class文件中我們只能找到一個對sss的表示:

  

  abh: ; sss


  在程序執行的時候Constant Pool會儲存在Method Area而不是heap中

  另外對於內容為空的字符串常量會創建一個長度為內容為空的字符串放到Constant Pool中

  而且Constant Pool在運行期是可以動態擴展的

  

  

  關於String類的說明

  String使用private final char value[]來實現字符串的存儲也就是說String對象創建之後就不能再修改此對象中存儲的字符串內容就是因為如此才說String類型是不可變的(immutable)

  String類有一個特殊的創建方法就是使用雙引號來創建例如new String(i am)實際創建了

  String對象一個是i am通過雙引號創建的另一個是通過new創建的只不過他們創建的時期不同

  一個是編譯期一個是運行期!

  java對String類型重載了+操作符可以直接使用+對兩個字符串進行連接

  運行期調用String類的intern()方法可以向String Pool中動態添加對象

  String的創建方法一般有如下幾種

  直接使用引號創建

  使用new String()創建

  使用new String(someString)創建以及其他的一些重載構造函數創建

  使用重載的字符串連接操作符+創建

  例

  

  String s = sss; //此語句同上 String s = sss; Systemoutprintln(s == s); //結果為true

  例

  

  String s = new String(sss); String s = sss; Systemoutprintln(s == s); //結果為false

  String s = new String(sss); s = sintern(); String s = sss; Systemoutprintln(s == s);

  

  

  

  例

  

  String s = new String(); String s = sss; String s = sss + ; String s = sss + s; Systemoutprintln(s == s); //true Systemoutprintln(s == s); //false Systemoutprintln(s == sintern()); //true


  例

  這個是The Java Language Specification中節的例子有了上面的說明這個應該不難理解了

  

  package testPackage; class Test { public static void main(String[] args) { String hello = Hello lo = lo; Systemoutprint((hello == Hello) + ); Systemoutprint((Otherhello == hello) + ); Systemoutprint((otherOtherhello == hello) + ); Systemoutprint((hello == (Hel+lo)) + ); Systemoutprint((hello == (Hel+lo)) + ); Systemoutprintln(hello == (Hel+lo)intern()); } } class Other { static String hello = Hello; } package other; public class Other { static String hello = Hello; }


  輸出結果為true true true true false true請自行分析!

  結果上面分析總結如下:

  單獨使用引號創建的字符串都是常量編譯期就已經確定存儲到String Pool中

  使用new String()創建的對象會存儲到heap中是運行期新創建的

  使用只包含常量的字符串連接符如aa + aa創建的也是常量編譯期就能確定已經確定存儲到String Pool中

  使用包含變量的字符串連接符如aa + s創建的對象是運行期才創建的存儲在heap中

  使用aa + s以及new String(aa + s)形式創建的對象是否加入到String Pool中我不太確定可能是必須調用intern()方法才會加入希望高手能回答!

  還有幾個經常考的面試題:

  

  

  String s = new String(s) ; String s = new String(s) ; 上面創建了幾個String對象? 答案:編譯期Constant Pool中創建運行期heap中創建


  

  

  String s = s; String s = s; s = s; s指向的對象中的字符串是什麼? 答案: s


From:http://tw.wingwit.com/Article/program/Java/ky/201311/28198.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.