最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java的字符串常量池StringTable詳解

 更新時間:2023年11月29日 09:05:10   作者:安然望川海  
這篇文章主要介紹了Java的字符串常量池StringTable詳解,JVM為了提高性能和減少內存開銷,在實例化字符串常量的時候進行了一些優(yōu)化,為 了減少在JVM中創(chuàng)建的字符串的數(shù)量,字符串類維護了一個字符串池,需要的朋友可以參考下

什么是字符串常量池

字符串的分配,和其他的對象分配一樣,耗費高昂的時間與空間代價。JVM為了提高性能和減少內存開銷,在實例化字符串常量的時候進行了一些優(yōu)化。為 了減少在JVM中創(chuàng)建的字符串的數(shù)量,字符串類維護了一個字符串池,每當代碼創(chuàng)建字符串常量時,JVM會首先檢查字符串常量池。如果字符串已經存在池中, 就返回池中的實例引用。如果字符串不在池中,就會實例化一個字符串并放到池中。

Java能夠進行這樣的優(yōu)化是因為字符串是不可變的,可以不用擔心數(shù)據沖突 進行共享

string的string Pool是一個圉定大小的Hashtable,默認值大小長度是1009。如果放進string Pool的string非常多,就會造成Hash沖突嚴重,從而導致鏈表會很長,而鏈表長了后直接會造成的影響就是當調用string.intern時性能會大幅下降。

參數(shù)設置

使用-xX :StringTablesize可設置stringTable的長度

在jdk6中stringTable是固定的,就是1009的長度,所以如果常量池中的字符串過多就會導致效率下降很快。StringTablesize設置沒有要求在jdk7中,stringTable的長度默認值是60013 jdk8開始,1009是可設置的最小值

字符串常量池中是不會存儲相同內容的字符串的(equals方法返回為true,即字面量相等)

常量池位置的調整

Java 6及以前,字符串常量池存放在永久代。 Java 7 中 Oracle 的工程師對字符串池的邏輯做了很大的改變,即將字符串常量池的位置調整到Java堆內。

所有的字符串都保存在堆(Heap)中,和其他普通對象一樣,這樣可以讓你在進行調優(yōu)應用時僅需要調整堆大小就可以了

字符串常量池概念原本使用得比較多,但是這個改動使得我們有足夠的理由讓我們重新考慮在Java 7 中使用string.intern()。

Java8元空間,字符串常量在堆內存中

為什么要從永久代調整位置到堆中?

因為我們在開發(fā)中會創(chuàng)建大量的字符串常量,回收效率低,導致永久代空間不足。放在堆里能及時回收內存

方法原理

常量與常量的拼接結果在常量池,原理是編譯期優(yōu)化

public class StringTest {
    public static final String A = "a";
    public static void main(String[] args) {
        String s = "a"+"b";//兩個字符串常量拼接
        String s1 = "ab";
        String s2 = A+"b";//常量引用和字符串常量拼接
        System.out.println(s == s1);
        System.out.println(s == s2);
        System.out.println(s2 == s1);
    }
}

以上三個字符串都存儲在常量池中,所以打印結果都是true 因為被final修飾的字符串會在編譯期放入常量池

只要其中有一個是變量,結果就在堆中。變量拼接的原理是stringBuilder

		String s1 = "ab";
        String s2 = "a";
        String s3 = s2+"b";

字節(jié)碼

在這里插入圖片描述

可以看到String s3 = s2+"b";的過程等價于

第6行表示new一個StringBuilder對象 (jdk5之前是StringBuffer)

第10行執(zhí)行構造方法, 14行表示調用append方法拼接“a”

19行同理拼接“b”, 然后第22行表示調用toString方法

StringBuilder sb = new StringBuilder();//6
        sb.append("a");//14
        sb.append("b");//19
        sb.toString();//22

查看StringBuilder源碼:oString方法new 了一個區(qū)別于常量池地址的新的String 對象

public String toString() {
	        // Create a copy, don't share the array
	        return new String(value, 0, count);
	    }

如果拼接的結果調用intern ()方法,則主動將常量池中還沒有的字符串對象放入池中,并返回此對象地址。

 private static void test2() {
        String s1 = "ab";
        String s2 = "a";
        String s3 = s2+"b";
        String s4 = s3.intern();
        System.out.println(s3 == s1);//false
        System.out.println(s4 == s1);//true
    }

intern 方法會先看常量池中是否有“ab”,若有,直接返回地址,若沒有,創(chuàng)建“ab”到常量池并返回結果。 所以s4的地址指向常量池中的“ab”;

append和+的效率

我們已經通過字節(jié)碼看到“a”+“b”會new一個StringBuilder,調用append方法并toString,此時new 了一個StringBuilder,new 了一個String,注意此時常量池不會創(chuàng)建“ab”常量

所以在一個循環(huán)里String a += "xxx"的效率是遠低于在循環(huán)中sb.append(“xxx”)最后toSring的效率的,后者少創(chuàng)建了相當于n-1個StringBuiler對象 再看StringBuiler的構造方法:

/**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuilder() {
        super(16);
    }
/**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

默認數(shù)組長度是16,如果拼接的操作遠大于16,也是會引起頻繁擴容的,所以如果知道字符串的最終長度不超過某個值,可以直接將這個值通過構造器傳入以提高性能

面試題

new string(“a”)創(chuàng)建了幾個對象?

private static void test4(){
        String s1 = new String("a");
    
    }

字節(jié)碼

0 new #14 <java/lang/String>
 3 dup
 4 ldc #7 <a>
 6 invokespecial #15 <java/lang/String.<init>>
 9 astore_0
10 return

可以看到答案是兩個,new一個Stirng對象字節(jié)碼第0行,方法區(qū)放入“a”對象對應字節(jié)碼第4行(如果之前常量池沒有的話)

new string(“a”) + new string(“b”)創(chuàng)建了幾個對象?

String s1 = new String("a") + new String("b");

字節(jié)碼

 0 new #8 <java/lang/StringBuilder>
 3 dup
 4 invokespecial #9 <java/lang/StringBuilder.<init>>
 7 new #14 <java/lang/String>
10 dup
11 ldc #7 <a>
13 invokespecial #15 <java/lang/String.<init>>
16 invokevirtual #10 <java/lang/StringBuilder.append>
19 new #14 <java/lang/String>
22 dup
23 ldc #11 <b>
25 invokespecial #15 <java/lang/String.<init>>
28 invokevirtual #10 <java/lang/StringBuilder.append>
31 invokevirtual #12 <java/lang/StringBuilder.toString>
34 astore_0
35 return

可以看到常量池兩個對象常量“a”和“b”(11和23行),兩個new的String對象(7和19),還有一個StringBudder對象(0),特別注意31行的toString方法又new了一個“ab”的對象,而不放入字符串常量池,所以答案是6個

intern方法的更改

private static void test5(){
        String s1 = new String("a") ;
        s1.intern();
        String s2 = "a";
        System.out.println(s1 == s2);//false

    }

這里結果為false,很正常,注意的是s1.intern();并沒有返回重新賦值,如果修改為s1 = s1.intern();則結果true;

再修改一下:

private static void test5(){
        String s1 = new String("a") + new String ("b");
        s1.intern();
        String s2 = "ab";
        System.out.println(s1 == s2);//false?

    }

我們知道第一段代碼并沒有在常量池生成“ab”,第二行代碼生成了但是沒返回,結果是不是false?

很遺憾,jdk6及其之前是false,但是jdk7以后是true,為什么呢,這就是提一下intern在jdk7之后做的改動:如果常量池沒有對應的字符串常量------- jdk6以及之前,該方法會在常量池中創(chuàng)建新的對象,這很好理解返回結果是false,但是在jdk7之后,如果堆空間已經有了我們第一行new的“ab”后,只會在常量池創(chuàng)建一個指向前者的指針,所以返回是true;更進一步,去掉代碼s1.intern();則結果就是false了,因為這時候常量池中是新的對象,而非第一個對象的指針

如果你現(xiàn)在回頭看上一個案例,為應該發(fā)現(xiàn)的是重點是String s1 = new String(“a”) ;和String s1 = new String(“a”) + new String (“b”);的區(qū)別:后者沒有在常量池生成“ab”對象.

到此這篇關于Java的字符串常量池StringTable詳解的文章就介紹到這了,更多相關StringTable詳解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java有序鏈表的合并實現(xiàn)方法

    Java有序鏈表的合并實現(xiàn)方法

    這篇文章主要通過兩個例題為大家介紹一下Java合并兩個及以上有序鏈表的實現(xiàn)方法,文中的示例代碼講解詳細,具有一定的學習價值,需要的可以參考一下
    2023-04-04
  • SpringBoot整合MyBatis Plus實現(xiàn)基本CRUD與高級功能

    SpringBoot整合MyBatis Plus實現(xiàn)基本CRUD與高級功能

    Spring Boot是一款用于快速構建Spring應用程序的框架,而MyBatis Plus是MyBatis的增強工具,本文將詳細介紹如何在Spring Boot項目中整合MyBatis Plus,并展示其基本CRUD功能以及高級功能的實現(xiàn)方式,需要的朋友可以參考下
    2024-02-02
  • 十大常見Java String問題_動力節(jié)點Java學院整理

    十大常見Java String問題_動力節(jié)點Java學院整理

    本文介紹Java中關于String最常見的10個問題,需要的朋友參考下吧
    2017-04-04
  • IDEA實用好用插件推薦及使用方法教程詳解(必看)

    IDEA實用好用插件推薦及使用方法教程詳解(必看)

    這篇文章主要介紹了IDEA實用好用插件推薦及使用方法教程,本文通過實例截圖相結合給大家介紹的非常詳細,對大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • Java數(shù)據結構與算法之單鏈表深入理解

    Java數(shù)據結構與算法之單鏈表深入理解

    這篇文章主要介紹了Java數(shù)據結構與算法之單鏈表深入理解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Java棋類游戲實踐之中國象棋

    Java棋類游戲實踐之中國象棋

    這篇文章主要為大家詳細介紹了Java棋類游戲中的中國象棋實現(xiàn)方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-02-02
  • spring boot如何使用AOP統(tǒng)一處理web請求

    spring boot如何使用AOP統(tǒng)一處理web請求

    這篇文章主要介紹了spring boot如何使用AOP統(tǒng)一處理web請求,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • 基于SpringBoot多線程@Async的使用體驗

    基于SpringBoot多線程@Async的使用體驗

    這篇文章主要介紹了SpringBoot多線程@Async的使用體驗,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java控制臺實現(xiàn)聊天程序

    java控制臺實現(xiàn)聊天程序

    這篇文章主要為大家詳細介紹了java控制臺實現(xiàn)聊天程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java框架解說之BIO NIO AIO不同IO模型演進之路

    Java框架解說之BIO NIO AIO不同IO模型演進之路

    網上很多IO資料,對新手來說,越看越暈。根據自己的理解,總結對比了一下BIO、NIO、AIO,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10

最新評論

石柱| 集贤县| 盐亭县| 苍梧县| 伽师县| 巫溪县| 沙湾县| 天祝| 陕西省| 中超| 准格尔旗| 广宗县| 神池县| 白河县| 利辛县| 古田县| 溧阳市| 黔东| 布拖县| 黔江区| 高要市| 西乌珠穆沁旗| 措勤县| 临高县| 将乐县| 清徐县| 仁寿县| 平湖市| 台东市| 台江县| 鄢陵县| 岑巩县| 搜索| 伊川县| 聂荣县| 太康县| 漠河县| 胶州市| 宁城县| 宿迁市| 武冈市|