c++ 返回string_JVM系列之:String.intern和stringTable

4e193e0a8ce38f1e392eedf60dc22b11.png

簡介

StringTable是什么?它和String.intern有什么關系呢?在字符串對象的創建過程中,StringTable有起到了什么作用呢?

一切的答案都在本文中,快來看看吧。

intern簡介

intern是String類中的一個native方法,所以它底層是用c++來實現的。感興趣的同學可以去查看下JVM的源碼了解更多的內容。

這里我們主要談一下intern的作用。

intern返回的是這個String所代表的對象,怎么理解呢?

String class維護了一個私有的String pool, 這個String pool也叫StringTable,中文名字叫做字符串常量池。

當我們調用intern方法的時候,如果這個StringTable中已經包含了一個相同的String對象(根據equals(Object)方法來判斷兩個String對象是否相等),那么將會直接返回保存在這個StringTable中的String。

如果StringTable中沒有相同的對象,那么這個String對象將會被加入StringTable,并返回這個String對象的引用。

所以,當且僅當 s.equals(t) 的時候s.intern() == t.intern()。

intern和字符串字面量常量

我們知道在類文件被編譯成class文件時,每個class文件都有一個常量池,常量池中存了些什么東西呢?

字符串常量,類和接口名字,字段名,和其他一些在class中引用的常量。

看一個非常簡單的java類:

public class SimpleString {public String site="www.flydean.com";
}

然后看一下編譯出來的class文件中的Constant Pool:

Constant pool:#1 = Methodref          #2.#3          // java/lang/Object."<init>":()V#2 = Class              #4             // java/lang/Object#3 = NameAndType        #5:#6          // "<init>":()V#4 = Utf8               java/lang/Object#5 = Utf8               <init>#6 = Utf8               ()V#7 = String             #8             // www.flydean.com#8 = Utf8               www.flydean.com#9 = Fieldref           #10.#11        // com/flydean/SimpleString.site:Ljava/lang/String;#10 = Class              #12            // com/flydean/SimpleString#11 = NameAndType        #13:#14        // site:Ljava/lang/String;#12 = Utf8               com/flydean/SimpleString#13 = Utf8               site#14 = Utf8               Ljava/lang/String;#15 = Utf8               Code#16 = Utf8               LineNumberTable#17 = Utf8               LocalVariableTable#18 = Utf8               this#19 = Utf8               Lcom/flydean/SimpleString;#20 = Utf8               SourceFile#21 = Utf8               SimpleString.java

上面的結果,我們可以看到class常量池中的index 7存放了一個字符串,這個字符串的實際內容存放在index 8中,是一個變種的Utf8的編碼。

#7 = String             #8             // www.flydean.com#8 = Utf8               www.flydean.com

好了,現在問題來了,class文件中的常量池在運行時需要轉換成為JVM能夠識別的運行時常量池,這個運行時的常量池和StringTable和intern有什么關系呢?

9200caca490d9f6c5c0f638eda446ed2.png

在java對象的實例化過程中,所有的字符串字面量都會在實例化的時候自動調用intern方法。

如果是第一次調用,則會創建新的String對象,存放在String Table中,并返回該String對象的引用。

分析intern返回的String對象

從上面的圖中,我們也可以出來String Table中存儲的是一個String對象,它和普通的String對象沒有什么區別,也分為對象頭,底層的byte數組引用,int hash值等。

如果你不相信,可以使用JOL來進行分析:

log.info("{}", ClassLayout.parseInstance("www.flydean.com".intern()).toPrintable());

看下輸出結果:

INFO com.flydean.StringInternJOL - java.lang.String object internals:OFFSET  SIZE      TYPE DESCRIPTION                               VALUE0     4           (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)4     4           (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4           (object header)                           77 1a 06 00 (01110111 00011010 00000110 00000000) (399991)12     4    byte[] String.value                              [119, 119, 119, 46, 102, 108, 121, 100, 101, 97, 110, 46, 99, 111, 109]16     4       int String.hash                               020     1      byte String.coder                              021     1   boolean String.hashIsZero                         false22     2           (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total

分析實際的問題

有了上面的知識,讓我們分析一下下面的實際問題吧:

String a =new String(new char[]{'a','b','c'});String b = a.intern();System.out.println(a == b);String x =new String("def");String y = x.intern();System.out.println(x == y);

兩個很簡單的例子,答案是什么呢? 答案是true和false。

第一個例子按照上面的原理很好理解,在構建String a的時候,String table中并沒有”abc“這個字符串實例。所以intern方法會將該對象添加到String table中,并返回該對象的引用。

所以a和b其實是一個對象,返回true。

那么第二個例子呢?初始化String的時候,不是也沒有”def“這個字符串嗎?為什么回返回false呢?

還記得我們上面一個小節分析的嗎?所有的字符串字面量在初始化的時候會默認調用intern方法。

也就是說”def“在初始化的時候,已經調用了一次intern了,這個時候String table中已經有”def“這個String了。

所以x和y是兩個不同的對象,返回的是false。

注意,上面的例子是在JDK7+之后運行的,如果你是在JDK6中運行,那么得到的結果都是false。

JDK6和JDK7有什么不同呢?

在JDK6中,StringTable是存放在方法區中的,而方法區是放在永久代中的。每次調用intern方法,如果String Table中不存在該String對象,則會將該String對象進行一次拷貝,并返回拷貝后String對象的引用。

因為做了一次拷貝,所以引用的不是同一個對象了。結果為false。

在JDK7之后,StringTable已經被轉移到了java Heap中了,調用intern方法的時候,StringTable可以直接將該String對象加入StringTable,從而指向的是同一個對象。

G1中的去重功能

如果頻繁的進行String的復制,實際上是非常消耗內存空間的。所以在G1垃圾回收器中,可以使用下面的:

-XX:+UseStringDeduplication

來開啟String的去重功能。

我們還記得String對象的底層結構吧,就是一個byte[]數組,String去重的原理就是讓多個字符串對象底層的byte數組指向同一個地方。從而節省內存。

我們可以通過使用:

-XX:+PrintStringTableStatistics

參數來查看StringTable的大小。并通過:

-XX:StringTableSizen=n

來指定StringTable的大小。

總結

本文講了String.intern和String table的關系,如果有什么錯誤或者遺漏的地方,歡迎大家留言給我!

本文作者:flydean程序那些事本文鏈接:http://www.flydean.com/jvm-string-intern/本文來源:flydean的博客歡迎關注我的公眾號:程序那些事,更多精彩等著您!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/534050.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/534050.shtml
英文地址,請注明出處:http://en.pswp.cn/news/534050.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

conda install 換源_ubuntu更換pip install,apt-get,conda install 成國內源

# 默認注釋了源碼鏡像以提高 apt update 速度&#xff0c;如有需要可自行取消注釋deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe multiverse# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted universe mu…

python幫助文檔中查看內置函數_PYTHON官方文檔內置函數整理

一、數學運算類 abs(x) 求絕對值 1 、參數可以是整型&#xff0c;也可以是復數 2 、若參數是復數&#xff0c;則返回復數的模 complex([real[, imag]]) 創建一個復數 divmod(a, b) 分別取商和余數 注意&#xff1a;整型、浮點型都可以 float([x]) 將一個字符串或數轉換為浮點數…

計算機二級指針,C語言——二級指針

二級指針的概念首先任何值都有地址&#xff0c;一級指針的值雖然是地址&#xff0c;但這個地址做為一個值亦需要空間來存放&#xff0c;是空間就具有地址&#xff0c;這就是存放地址這一值的空間所具有的地址&#xff0c;二級指針就是為了獲取這個地址&#xff0c;一級指針所關…

華為 虛擬鍵盤_華為mate30 pro虛擬機械鍵盤特有體驗,雖是虛擬,但卻感受逼真...

華為Mate30 pro已于26日在國內正式發布了。此外&#xff0c;根據了解華為Mate30系列現在已經突破了5億的銷售額。看來&#xff0c;華為的這個下半年旗艦手機非常受歡迎啊。華為Mate30系列現在在國內已經發布了&#xff0c;其整體感官看上去與海外的沒有多大的區別。其實&#x…

python 如何快速判斷列表是否相同_Python-檢查列表中的所有元素是否相同

小編典典 通用方法&#xff1a; def checkEqual1(iterator): iterator iter(iterator) try: first next(iterator) except StopIteration: return True return all(first rest for rest in iterator) 單線&#xff1a; def checkEqual2(iterator): return len(set(iterator)…

計算機有什么著名基金經理排名,百萬年薪的基金經理,都是什么專業出身?!...

有人會說了“小嗶君你四不四撒&#xff01;基金經理肯定是金融專業出身的咯&#xff1f;不然嘞&#xff1f;”但事實的真相是許多基金經理都并非科班出身這要從基金經理的晉升機制說起了&#xff01;如下圖基金經理都是從研究員做起的&#xff01;那么問題來了&#xff0c;如何…

遍歷children_589. N叉樹的前序遍歷

589. N叉樹的前序遍歷給定一個 N 叉樹&#xff0c;返回其節點值的前序遍歷。例如&#xff0c;給定一個 3叉樹 :返回其前序遍歷: [1,3,5,6,2,4]。說明: 遞歸法很簡單&#xff0c;你可以使用迭代法完成此題嗎?題解&#xff1a;既然是樹的遍歷&#xff0c;那么一共就是兩種思路&a…

計算機護理職稱考試報名時間2015,護理職稱考試怎么報名?

護理職稱考試報名流程&#xff1a;網上預報名-現場確認-報名繳費。護理職稱考試網上預報名及網上繳費均在中國衛生人才網&#xff0c;護理職稱考試報名現場確認則按屬地原則在單位或戶籍所在地的衛計局。護理職稱考試報名流程詳解一、網上預報名考生需在規定的時間內登錄中國衛…

怎么用python編程前二n-1項的等差數列的和_python 等差數列末項計算方式

等差數列末項計算 題目內容&#xff1a; 給出一個等差數列的前兩項a1&#xff0c;a2&#xff0c;求第n項是多少 可以使用以下語句實現非負整數n的輸入&#xff1a; nint(input()) 輸入格式: 三行&#xff0c;包含三個整數a1&#xff0c;a2&#xff0c;n 輸出格式&#xff1a; 一…

圖紙中bs是什么意思_園建施工圖中WL、BL、FL、TW、SL分別是什么意思

展開全部WL是水面標高來BL池底自標高FL地面標bai高TW墻頂標高SL 土面標高其他其他一些常du用的注解&#xff1a;PA種植區FF室內樓zhi地面標FG室外軟景完成dao面標高BC路沿底標高BS踏步底標高BR欄桿扶手底標高TR欄桿扶手頂標高SL結構板頂標高擴展資料本書圍繞園林工程建設主題&a…

計算機未顯示移動硬盤,電腦不顯示移動硬盤怎么辦_移動硬盤已連接不顯示解決教程...

最近有很多小伙伴咨詢小編&#xff0c;電腦不顯示移動硬盤怎么辦&#xff0c;怎么設置才能恢復呢&#xff1f;其實操作內容很簡單&#xff0c;嘗試刪除你的USB3.0可擴展主機控制器,再掃描硬件改動&#xff0c;今天就由小編來告訴你&#xff0c;移動硬盤已連接不顯示的解決方法。…

八個角最多可以把平面分成多少部分?_一個空間最多能被分成幾塊?

相信大家在小學奧數中都遇到這樣一個問題&#xff1a;4條直線最多能將平面分成幾部分&#xff1f;這個問題并不能難倒我們&#xff0c;但是如果將問題改為&#xff1a;4個平面最多能將空間分為幾部分&#xff1f;這下子我們可能就要放棄了。為了解決這個問題&#xff0c;今天我…

ios 不被遮擋 陰影_IOS開發之Bug--iOS7View被導航欄遮擋問題的解決

在實際開發中&#xff0c;遇到在UITextView的frame等于當前控制器的View的frame的情況下&#xff0c;然后運行的時候&#xff0c;發現控制器的Frame的高度y值會從導航條的位置64變化到0。導致UITextView的frame也跟著一起移動。這個問題本質其實就是iOS7View被導航欄遮擋問題&a…

破壞計算機信息系統功能罪,破壞計算機信息系統罪

破壞計算機信息系統罪2010年05月05日19:42法律咨詢 我要評論一、概念&nbsp&nbsp&nbsp&nbsp破壞計算機信息系統罪(刑法第286條)&#xff0c;是指違反國家規定&#xff0c;對計算機信息系統功能或計算機信息系統中存儲、處理或者傳輸的數據和應用程序進行破壞…

python解析html xml最好的模塊_Python HTML/XML解析器BeautifulSoup(爬蟲解析器)

The Dormouses storyOnce upon a time there were three little sisters; and their names were Elsie, Lacie and Tillie; and they lived at the bottom of a well....

ffmpeg運行在服務器上,FFMPEG安裝在服務器上

我有一個在線服務器(共享主機方案)在Linux中&#xff0c;我不知道很多關于Linux的東西&#xff0c;我正在嘗試安裝ffmpeg。FFMPEG安裝在服務器上當安裝正在運行我得到這個消息&#xff0c;并停止安裝...Installation of MPlayer-1.0rc1.tar.bz2 ....... started% Total % Recei…

python csv pandas_Python Pandas——Read_csv詳解

目前最常用的數據保存格式可能就是CSV格式了&#xff0c;數據分析第一步就是獲取數據&#xff0c;怎樣讀取數據至關重要。 本文將以pandas read_csv方法為例&#xff0c;詳細介紹read_csv數據讀取方法。再數據讀取時進行數據預處理&#xff0c;這樣不僅可以加快讀取速度&#x…

python3兼容python2 print_python 字符串 r raw Python2 和 Python3 的區別及兼容技巧

前言最近 Python 之父 Guido van Rossum(龜爺)終于在 Python 官方郵件組落實了 Python 2.7 的終焉之日(EOL)。說的是 Python 2.7 的 EOL 日期最終確定為 2020 年 1 月 1 日&#xff0c;之后不會有任何更新&#xff0c;包括源碼的安全補丁。所以兼容Python3已經可以說非常必要了…

nginx搭建文件服務器腳本,基于docker搭建nginx文件服務器的方法步驟

1.在本機新建配置文件docker_nginx.confserver {listen 7070;server_name localhost;charset utf-8;location /files {#在docker內nginx的目錄alias /home/files;expires 1d;allow all;autoindex on;}2.啟動命令docker run --name nginx -d -p 7070:7070 -v D:\dev\nginx-1.13.…

python運行不了指令_python不是內部命令或外部命令,也不是可執行程序解決方法...

簡述 常見于新手初裝python&#xff0c;然后忘記勾選設置環境變量(PATH)&#xff0c;或者沒有重啟&#xff0c;然后運行教程中的python命令時出現。 有兩個解決方法&#xff1a;1.設置環境變量&#xff0c;然后重啟。 2.新建命令。 如果你打算同時安裝多個python版本&#xff0…