日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

字符串常量池StringTable 你真的了解么

發布時間:2023/12/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符串常量池StringTable 你真的了解么 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本篇目錄

  • 1、 String的基本特性
  • 2、 String的內存分配
  • 3、 字符串拼接操作
    • 3.1 字符串拼接
    • 3.2 拼接操作與append的效率對比
  • 4、 intern()的使用
    • 4.1 new String("ab")會創建幾個對象,new String("a")+new String("b")呢
    • 4.2 關于String.intern()的問題
    • 4.3 總結String的intern()的使用

1、 String的基本特性

? String:字符串,使用一對""引起來表示。

? String sl = "hello"//字面量的定義方式 ? String s2 = new String"hello") ;

? String聲明為final的, 不可被繼承
? String實現了Serializable接口:表示字符串是支持序列化的。 實現了Comparable接口:表示String可以比較大小
? String在jdk8及以前內部定義了final char[] value用于存儲字符串數據。jdk9時改為byte[]

public final class String implements java.io.Serializable, Comparable<String>,CharSequence { @Stable private final byte[] value; }

結論: String再也不用char[] 來存儲啦,改成了byte[] 加上編碼標記,節約了一些空間。StringBuffer和StringBuilder也做了一些修改。

? String:代表不可變的字符序列。簡稱:不可變性。

  • 當對字符串重新賦值時,需要重寫指定內存區域賦值,不能使用原有的value進行賦值。
  • 當對現有的字符串進行連接操作時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值。
  • 當調用String的replace()方法修改指定字符或字符串時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值。

? 通過字面量的方式(區別于new)給一個字符串賦值,此時的字符串值聲明在字符串常量池中。

/*** String的基本使用:體現String的不可變性*/ public class StringTest1 {@Testpublic void test1() {String s1 = "abc";//字面量定義的方式,"abc"存儲在字符串常量池中String s2 = "abc";s1 = "hello";System.out.println(s1 == s2);//判斷地址:true System.out.println(s1);// helloSystem.out.println(s2);//abc}@Testpublic void test2() {String s1 = "abc";String s2 = "abc";s2 += "def";System.out.println(s2);//abcdefSystem.out.println(s1);//abc}@Testpublic void test3() {String s1 = "abc";String s2 = s1.replace('a', 'm');System.out.println(s1);//abcSystem.out.println(s2);//mbc} }

? 字符串常量池中是不會存儲相同內容的字符串的。

  • String的String Pool 是一個固定大小的Hashtable,默認值大小長度是1009。如果放進StringPool的String非常多, 就會造成Hash沖突嚴重,從而導致鏈表會很長,而鏈表長了后直接會造成的影響就是當調用String. intern時性能會大幅下降。
  • 使用一XX: StringTableSize可設置StringTable的長度
  • 在jdk6中StringTable是固定的,就是1009的長度,所以如果常量池中的字符串過多就會導致效率下降很快。StringTableSize設 置沒有要求
  • 在jdk7中,StringTable的長度默認值是60013
  • jdk8開始,1009是StringTable長度可設置的最小值

2、 String的內存分配

  • 在Java語言中有8種基本數據類型和一種比較特殊的類型String。這些 類型為了使它們在運行過程中速度更快、更節省內存,都提供了一種常量池的概念。

  • 常量池就類似一.個Java系統級別提供的緩存。8種基本數據類型的常量 池都是系統協調的,String類 型的常量池比較特殊。它的主要使用方法有兩種。

    • 直接使用雙引號聲明出來的String對象會直接存儲在常量池中。 比如: String info = “abc” ;
    • 如果不是用雙引號聲明的String對象,可以使用String提供的intern()方法。這個后面重點聊。
  • Java 6及以前,字符串常量池存放在永久代。

  • Java 7中Oracle的工程師對字符串池的邏輯做了很大的改變,即將字符串常量池的位置調整到Java堆內。

    • 所有的字符串都保存在堆(Heap)中,和其他普通對象一樣,這樣可以讓你在進行調優應用時僅需要調整堆大小就可以了。
    • 字符串常量池概念原本使用得比較多,但是這個改動使得我們有足夠的理由讓我們重新考慮在Java 7中使用String. intern()。
  • Java8元空間,字符串常量在堆

StringTable為什么要調整?
①永久代permSize默認比較小;
②永久代的垃圾回收頻率低;

3、 字符串拼接操作

  • 常量與常量的拼接結果在常量池,原理是編譯期優化
  • 常量池中不會存在相同內容的常量。
  • 只要其中有一個是變量,結果就在堆中。變量拼接的原理是StringBuilder
  • 如果拼接的結果調用intern()方法,則主動將常量池中還沒有的字符串對象放入池中,并返回此對象地址。
  • @Testpublic void test1(){String s1 = "a" + "b" + "c";//編譯期優化:等同于"abc"String s2 = "abc"; //"abc"一定是放在字符串常量池中,將此地址賦給s2/** 最終.java編譯成.class,再執行.class* String s1 = "abc";* String s2 = "abc"*/System.out.println(s1 == s2); //trueSystem.out.println(s1.equals(s2)); //true}@Testpublic void test2(){String s1 = "javaEE";String s2 = "hadoop";String s3 = "javaEEhadoop";String s4 = "javaEE" + "hadoop";//編譯期優化//如果拼接符號的前后出現了變量,則相當于在堆空間中new String(),具體的內容為拼接的結果:javaEEhadoopString s5 = s1 + "hadoop";String s6 = "javaEE" + s2;String s7 = s1 + s2;System.out.println(s3 == s4);//trueSystem.out.println(s3 == s5);//falseSystem.out.println(s3 == s6);//falseSystem.out.println(s3 == s7);//falseSystem.out.println(s5 == s6);//falseSystem.out.println(s5 == s7);//falseSystem.out.println(s6 == s7);//false//intern():判斷字符串常量池中是否存在javaEEhadoop值,如果存在,則返回常量池中javaEEhadoop的地址;//如果字符串常量池中不存在javaEEhadoop,則在常量池中加載一份javaEEhadoop,并返回次對象的地址。String s8 = s6.intern();System.out.println(s3 == s8);//true}

    3.1 字符串拼接

    @Testpublic void test3(){String s1 = "a";String s2 = "b";String s3 = "ab";/*如下的s1 + s2 的執行細節:(變量s是我臨時定義的)① StringBuilder s = new StringBuilder();② s.append("a")③ s.append("b")④ s.toString() --> 約等于 new String("ab")補充:在jdk5.0之后使用的是StringBuilder,在jdk5.0之前使用的是StringBuffer*/String s4 = s1 + s2;//System.out.println(s3 == s4);//false}/*1. 字符串拼接操作不一定使用的是StringBuilder!如果拼接符號左右兩邊都是字符串常量或常量引用,則仍然使用編譯期優化,即非StringBuilder的方式。2. 針對于final修飾類、方法、基本數據類型、引用數據類型變量的結構時,能使用上final的時候建議使用上。*/@Testpublic void test4(){final String s1 = "a";final String s2 = "b";String s3 = "ab";String s4 = s1 + s2;System.out.println(s3 == s4);//true}@Testpublic void test5(){String s1 = "javaEEhadoop";String s2 = "javaEE";String s3 = s2 + "hadoop";System.out.println(s1 == s3);//falsefinal String s4 = "javaEE";//s4:常量String s5 = s4 + "hadoop";System.out.println(s1 == s5);//true}

    3.2 拼接操作與append的效率對比

    append效率要比字符串拼接高很多!

    /*體會執行效率:通過StringBuilder的append()的方式添加字符串的效率要遠高于使用String的字符串拼接方式!詳情:1、 StringBuilder的append()的方式:自始至終中只創建過一個StringBuilder的對象使用String的字符串拼接方式:創建過多個StringBuilder和String的對象2、 使用String的字符串拼接方式:內存中由于創建了較多的StringBuilder和String的對象,內存占用更大;如果進行GC,需要花費額外的時間。改進的空間:在實際開發中,如果基本確定要前前后后添加的字符串長度不高于某個限定值highLevel的情況下,建議使用構造器實例化:StringBuilder s = new StringBuilder(highLevel);//new char[highLevel]*/@Testpublic void test6(){long start = System.currentTimeMillis(); // method1(100000);//4014method2(100000);//7long end = System.currentTimeMillis();System.out.println("花費的時間為:" + (end - start));}public void method1(int highLevel){String src = "";for(int i = 0;i < highLevel;i++){src = src + "a";//每次循環都會創建一個StringBuilder、String} // System.out.println(src);}public void method2(int highLevel){//只需要創建一個StringBuilderStringBuilder src = new StringBuilder();for (int i = 0; i < highLevel; i++) {src.append("a");} // System.out.println(src);}

    4、 intern()的使用

    如果不是用雙引號聲明的String對象,可以使用String提供的intern方法: intern方法會從字符串常量池中查詢當前字符串是否存在,若不存在就會將當前字符串放入常量池中。
    比如:

    String myInfo = new String("I love u").intern()

    也就是說,如果在任意字符串上調用String. intern方法,那么其返回結果所指向的那個類實例,必須和直接以常量形式出現的字符串實例完全相同。因此,下 列表達式的值必定是true:

    "a" + "b" + "c".intern()== "abc";

    通俗點講,Intern() String就是確保字符串在內存里只有一份拷貝,這樣可以節約內存空間,加快字符串操作任務的執行速度。注意,這個值會被存放在字符串內部池(String Intern Pool)。

    4.1 new String(“ab”)會創建幾個對象,new String(“a”)+new String(“b”)呢

    public class StringNewTest {public static void main(String[] args) { // String str = new String("ab");String str = new String("a") + new String("b");} }
    • new String(“ab”)會創建幾個對象?看字節碼,就知道是兩個。

      • 一個對象是:new關鍵字在堆空間創建的
      • 另一個對象是:字符串常量池中的對象"ab"。 字節碼指令:ldc
    • new String(“a”) + new String(“b”)呢?

      • 對象1:new StringBuilder()
      • 對象2: new String(“a”)
      • 對象3: 常量池中的"a"
      • 對象4: new String(“b”)
      • 對象5: 常量池中的"b"
      • 4.22

    4.2 關于String.intern()的問題

    /*** 如何保證變量s指向的是字符串常量池中的數據呢?* 有兩種方式:* 方式一: String s = "shkstart";//字面量定義的方式* 方式二: 調用intern()* String s = new String("shkstart").intern();* String s = new StringBuilder("shkstart").toString().intern();**/ public class StringIntern {public static void main(String[] args) {String s = new String("1");String s1 = s.intern();//調用此方法之前,字符串常量池中已經存在了"1"String s2 = "1";//s 指向堆空間"1"的內存地址//s1 指向字符串常量池中"1"的內存地址//s2 指向字符串常量池已存在的"1"的內存地址 所以 s1==s2System.out.println(s == s2);//jdk6:false jdk7/8:falseSystem.out.println(s1 == s2);//jdk6: true jdk7/8:trueSystem.out.println(System.identityHashCode(s));//491044090System.out.println(System.identityHashCode(s1));//644117698System.out.println(System.identityHashCode(s2));//644117698//s3變量記錄的地址為:new String("11")String s3 = new String("1") + new String("1");//執行完上一行代碼以后,字符串常量池中,是否存在"11"呢?答案:不存在!!//在字符串常量池中生成"11"。如何理解:jdk6:創建了一個新的對象"11",也就有新的地址。// jdk7:此時常量中并沒有創建"11",而是創建一個指向堆空間中new String("11")的地址s3.intern();//s4變量記錄的地址:使用的是上一行代碼代碼執行時,在常量池中生成的"11"的地址String s4 = "11";System.out.println(s3 == s4);//jdk6:false jdk7/8:true} }


    4.3 總結String的intern()的使用

    • jdk1.6中,將這個字符串對象嘗試放入串池。
      • ?如果字符串常量池中有,則并不會放入。返回已有的串池中的對象的地址
      • ?如果沒有,會把此對象復制一份,放入串池,并返回串池中的對象地址
    • Jdk1.7起,將這個字符串對象嘗試放入串池。
      • ?如果字符串常量池中有,則并不會放入。返回已有的串池中的對象的地址
      • ?如果沒有,則會把對象的引用地址復制一份,放入串池,并返回串池中的引用地址

    總結

    以上是生活随笔為你收集整理的字符串常量池StringTable 你真的了解么的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。