亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解JVM 中的StringTable

 更新時間:2021年03月05日 08:35:20   作者:萌新J  
這篇文章主要介紹了JVM 中的StringTable,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

是什么

字符串常量池是 JVM中的一個重要結構,用于存儲JVM運行時產(chǎn)生的字符串。在JDK7之前在方法區(qū)中,存儲的是字符串常量。而字符串常量池在 JDK7開始移入堆中,隨之而來的是除了存儲字符串常量外,還可以存儲字符串引用(因為在堆中,引用堆中的字符串常量很方便,所以可以存儲引用)。這使得很多字符串的操作在 JDK7中和在之前的版本中執(zhí)行是不同的結果。這也是為什么字符串相關的問題是如此具有迷惑性的原因之一。

底層

String:在 JDK9之前,String底層是使用 char數(shù)組來存儲字符串數(shù)據(jù)的,而在 JDK9開始,使用 byte數(shù)組+編碼來代替 char數(shù)組,這是為了節(jié)省空間,因為不同編碼的數(shù)據(jù)占空間不一樣,很多單位數(shù)據(jù)只需要一個 byte(8字節(jié)) 就可以存儲,而使用 char(16字節(jié))就會浪費多余的空間。

字符串常量池:底層使用 HashTable來存儲字符串,在 JDK6 HashTable的數(shù)組長度是1006,JDK7開始變成了 60013,這是為了避免存儲字符串過多導致鏈表長度過長從而查詢效率降低??梢允褂脜?shù) -XX:StringTableSize=來設置 StringTable數(shù)組的長度。

常見問題字符串相加

1、對于字符串常量相加,編譯器會優(yōu)化成直接相加。

如 String ss = "a" + "b",在編譯器的優(yōu)化下,實際上只會創(chuàng)建一個 "ab" 字符串。

而 final String s1 = "a"; String s2 = s1+"b",除了創(chuàng)建字符串 "a"外,只會創(chuàng)建 "ab"。

操作相關字符串如下:

可以看到只對字符串 "a"、"ab"進行了入池操作(ldc)

2、對于包含字符串變量的相加,不會在字符串常量池中創(chuàng)建對應的字符串。
如 String s1 = "a"; String s2 = s1 + "b",執(zhí)行完后字符串常量池中只會包含 "a"、"b" 字符串。

對于 s1 + "b",下面是其字節(jié)碼操作

可以看到,相加操作實際上是調(diào)用 StringBuilder的append方法進行字符串拼接,然后調(diào)用它的 toString方法獲取返回值保存輸出,期間并沒有入池操作(ldc)。

由此得出的優(yōu)化建議:因為每次執(zhí)行一次包含非常量的字符串相加時,都進行了一次 StringBuilder對象的創(chuàng)建,所以如果需要多次連接,可以直接創(chuàng)建 StringBuilder對象,使用一個 StringBuilder對象進行字符串拼接,避免創(chuàng)建多個對象降低效率。

對象創(chuàng)建數(shù)量

對象,包括 new的對象以及字符串對象。

1、對于String ss = new String ("ab"),這個過程首先會在會在字符串常量池中創(chuàng)建一個 "ab"字符串常量,然后再在堆上創(chuàng)建一個 new String()的對象,在這個對象中會保存常量池中 "ab"的地址信息,最后在棧上創(chuàng)建一個局部變量 ss ,保存堆中創(chuàng)建的對象地址。所以全程創(chuàng)建了堆中的一個對象和字符串常量池中的一個對象。

2、new String("a") + new String("b")。嚴格來看,創(chuàng)建了六個對象。

首先new String("a")和 new String("b") ,分為創(chuàng)建了兩個對象。兩者相加時,會創(chuàng)建一個 StringBuilder對象,而在 StringBuilder.toString()方法中,也會創(chuàng)建一個 String對象

3、String s1 = "a", String s2 = "b", String s3 = "a" + "b" + s1 + "c" + s2;對應的字節(jié)碼如下:

字符串常量池中會有四個字符串對象,分別是 "a"、"b"、"ab"、"c"。在開始因為 s1、s2的賦值,會將 "a"、"b"分別加入字符串常量池,然后執(zhí)行第三步,運行順序是從左到右,首先執(zhí)行 "a" + "b" ,因為兩個都是常量,所以會因為編譯器的優(yōu)化直接返回 "ab",并且因為計算的兩個參數(shù)都是常量,所以直接加入字符串常量池,隨后因為與變量 s1相加,所以調(diào)用 StringBuilder的append方法,得到的結果保存到局部變量表中,所以引入常量 "c",因為是常量,所以還是會引入字符串常量池,然后與前面拼接得到的結果再次拼接,最后再與變量 s2相加,因為不是常量所以還是不會將結果加入字符串常量池。

除此之外,還需要注意,上面三種情況是在初始情況下,也就是字符串常量池中沒有要加入的字符串時的場景,如果字符串常量池中預先就包含要加入的字符串,那么就會直接將常量池中的對應的字符串地址返回給調(diào)用方。比如 String s1 = "a",在常量池中沒有 "a"時,創(chuàng)建的對象是 1個,而如果常量池中已經(jīng)存在,那么就會將其地址直接返回賦給 s1。那么創(chuàng)建的對象就是 0個了。

intern()與字符串相等判斷

intern()方法是 String類的一個native方法,作用是嘗試將調(diào)用這個方法的字符串對象加入字符串常量池中,然后返回常量池中存儲的值。在開頭說過,在 JDK7開始字符串常量池可以存儲字符串引用,導致字符串操作的過程可能會之前不一樣,從而得到不同的結果。

intern()方法的執(zhí)行:

1.6及之前:嘗試將當前字符串常量加入常量池,如果常量池存在就返回地址值;如果不存在就先加入常量池,然后再返回加入位置的地址值。

1.7開始:嘗試將當前字符串常量加入常量池,如果存在就將返回地址值;如果不存在就存入當前 String 字符串的地址值。

下面以一個例子來解釋一下,在JDK7和JDK7之前下面代碼執(zhí)行分別是什么結果。

@Test
 public void test1(){
  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);
 }

先說結論:

JDK7之前: false、false。

JDK7及之后:false、true。

原因:

1、首先先看上面 3------6行的,首先,第三行會在字符串常量池中添加 "1" ,然后在堆中創(chuàng)建一個對象,保存 "1"在常量池中的地址,再在局部變量表中添加一個 s保存堆中對象的地址。隨后執(zhí)行第四行,此時 s指向的字符串已經(jīng)在常量池中了,所以這一步無效,第五行因為常量池已經(jīng)存在 "1" ,所以 JDK7或之前執(zhí)行的邏輯是一樣的,直接將 "1"在常量池中的地址返回給 s2。然后判斷,s指向的是堆中的對象,而 s2指向的是常量池中的字符串常量,所以無論是 JDK7還是之前的都是 false。

2、然后再看下面 9-----12行。因為前面已經(jīng)在常量池中添加 "1",所以第9行會直接返回地址,然后執(zhí)行添加操作,創(chuàng)建字符串 "11",此時并沒有添加到常量池,然后執(zhí)行第10行,因為常量池不存在 "11",所以 JDK7之前直接加入常量池,JDK7及以后則直接將 "11"的地址存入常量池,而 s3則不變,還是保存的是常量池外的那個 "11"的地址值。然后執(zhí)行 11行,因為常量池已存在 "11",所以 s4就是返回 "11"的地址值,不同的是在 JDK7之前因為常量池保存的是 "11"常量,所以返回的是常量池中的地址值;而 JDK7 及以后常量池保存的是常量池外的 "11"的地址值,所以返回的是池外的地址值。所以最后判斷在 JDK7之前是 false,而在 JDK7開始是 true。

到此這篇關于JVM 中的StringTable的文章就介紹到這了,更多相關JVM 中的StringTable內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 解決springboot的JPA在Mysql8新增記錄失敗的問題

    解決springboot的JPA在Mysql8新增記錄失敗的問題

    這篇文章主要介紹了解決springboot的JPA在Mysql8新增記錄失敗的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • IDEA如何實現(xiàn)右鍵翻譯

    IDEA如何實現(xiàn)右鍵翻譯

    這篇文章主要介紹了IDEA如何實現(xiàn)右鍵翻譯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringCloud應用idea實現(xiàn)可相互調(diào)用的多模塊程序詳解

    SpringCloud應用idea實現(xiàn)可相互調(diào)用的多模塊程序詳解

    IDEA 全稱 IntelliJ IDEA,是java編程語言的集成開發(fā)環(huán)境。IntelliJ在業(yè)界被公認為最好的Java開發(fā)工具,尤其在智能代碼助手、代碼自動提示、重構、JavaEE支持、各類版本工具(git、svn等)、JUnit、CVS整合、代碼分析、 創(chuàng)新的GUI設計等方面的功能可以說是超常的
    2022-07-07
  • SpringBoot中Filter?bean如何添加到Servlet容器

    SpringBoot中Filter?bean如何添加到Servlet容器

    這篇文章主要介紹了SpringBoot中Filter bean是怎么被添加到Servlet容器中的,本文分步驟結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • mybatis-plus返回查詢總記錄數(shù)方式

    mybatis-plus返回查詢總記錄數(shù)方式

    這篇文章主要介紹了mybatis-plus返回查詢總記錄數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • spring boot教程之產(chǎn)生的背景及其優(yōu)勢

    spring boot教程之產(chǎn)生的背景及其優(yōu)勢

    這篇文章主要介紹了spring boot教程之產(chǎn)生的背景及其優(yōu)勢的相關資料,需要的朋友可以參考下
    2022-08-08
  • 淺談java中六大時間類的使用和區(qū)別

    淺談java中六大時間類的使用和區(qū)別

    下面小編就為大家?guī)硪黄獪\談java中六大時間類的使用和區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • SpringMVC架構的項目 js,css等靜態(tài)文件導入有問題的解決方法

    SpringMVC架構的項目 js,css等靜態(tài)文件導入有問題的解決方法

    下面小編就為大家?guī)硪黄猄pringMVC架構的項目 js,css等靜態(tài)文件導入有問題的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 如何基于java向mysql數(shù)據(jù)庫中存取圖片

    如何基于java向mysql數(shù)據(jù)庫中存取圖片

    這篇文章主要介紹了如何基于java向mysql數(shù)據(jù)庫中存取圖片,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02
  • 關于IDEA 2020.3 多窗口視圖丟失的問題

    關于IDEA 2020.3 多窗口視圖丟失的問題

    這篇文章主要介紹了關于IDEA 2020.3 多窗口視圖丟失的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12

最新評論