国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 Java Java基礎(chǔ) java常量池圖文詳解

java常量池圖文詳解

Nov 30, 2019 pm 04:36 PM
java

java常量池圖文詳解

java常量池是一個經(jīng)久不衰的話題,也是面試官的最愛,題目花樣百出,小菜早就對常量池有所耳聞,這次好好總結(jié)一下。

推薦:java視頻教程

jvm虛擬內(nèi)存分布:

1.jpg

程序計數(shù)器是jvm執(zhí)行程序的流水線,存放一些跳轉(zhuǎn)指令,這個太高深,小菜不懂。

本地方法棧是jvm調(diào)用操作系統(tǒng)方法所使用的棧。

虛擬機(jī)棧是jvm執(zhí)行java代碼所使用的棧。

方法區(qū)存放了一些常量、靜態(tài)變量、類信息等,可以理解成class文件在內(nèi)存中的存放位置。

虛擬機(jī)堆是jvm執(zhí)行java代碼所使用的堆。

Java中的常量池,實際上分為兩種形態(tài):靜態(tài)常量池和運(yùn)行時常量池。

所謂靜態(tài)常量池,即*.class文件中的常量池,class文件中的常量池不僅僅包含字符串(數(shù)字)字面量,還包含類、方法的信息,占用class文件絕大部分空間。

?而運(yùn)行時常量池,則是jvm虛擬機(jī)在完成類裝載操作后,將class文件中的常量池載入到內(nèi)存中,并保存在方法區(qū)中,我們常說的常量池,就是指方法區(qū)中的運(yùn)行時常量池。

接下來我們引用一些網(wǎng)絡(luò)上流行的常量池例子,然后借以講解。

String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hel" + "lo";
String s4 = "Hel" + new String("lo");
String s5 = new String("Hello");
String s6 = s5.intern();
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;
          
System.out.println(s1 == s2);  // true
System.out.println(s1 == s3);  // true
System.out.println(s1 == s4);  // false
System.out.println(s1 == s9);  // false
System.out.println(s4 == s5);  // false
System.out.println(s1 == s6);  // true

首先說明一點,在java 中,直接使用==操作符,比較的是兩個字符串的引用地址,并不是比較內(nèi)容,比較內(nèi)容請用String.equals()。

s1 == s2這個非常好理解,s1、s2在賦值時,均使用的字符串字面量,說白話點,就是直接把字符串寫死,在編譯期間,這種字面量會直接放入class文件的常量池中,從而實現(xiàn)復(fù)用,載入運(yùn)行時常量池后,s1、s2指向的是同一個內(nèi)存地址,所以相等。

s1 == s3這個地方有個坑,s3雖然是動態(tài)拼接出來的字符串,但是所有參與拼接的部分都是已知的字面量,在編譯期間,這種拼接會被優(yōu)化,編譯器直接幫你拼好,因此String s3 = "Hel" + "lo";在class文件中被優(yōu)化成String s3 = "Hello";,所以s1 == s3成立。

s1 == s4當(dāng)然不相等,s4雖然也是拼接出來的,但new String("lo")這部分不是已知字面量,是一個不可預(yù)料的部分,編譯器不會優(yōu)化,必須等到運(yùn)行時才可以確定結(jié)果,結(jié)合字符串不變定理,鬼知道s4被分配到哪去了,所以地址肯定不同。配上一張簡圖理清思路:

2.jpgs1 == s9也不相等,道理差不多,雖然s7、s8在賦值的時候使用的字符串字面量,但是拼接成s9的時候,s7、s8作為兩個變量,都是不可預(yù)料的,編譯器畢竟是編譯器,不可能當(dāng)解釋器用,所以不做優(yōu)化,等到運(yùn)行時,s7、s8拼接成的新字符串,在堆中地址不確定,不可能與方法區(qū)常量池中的s1地址相同。

3.jpg

s4 == s5已經(jīng)不用解釋了,絕對不相等,二者都在堆中,但地址不同。

s1 == s6這兩個相等完全歸功于intern方法,s5在堆中,內(nèi)容為Hello ,intern方法會嘗試將Hello字符串添加到常量池中,并返回其在常量池中的地址,因為常量池中已經(jīng)有了Hello字符串,所以intern方法直接返回地址;而s1在編譯期就已經(jīng)指向常量池了,因此s1和s6指向同一地址,相等。

至此,我們可以得出三個非常重要的結(jié)論:

必須要關(guān)注編譯期的行為,才能更好的理解常量池。

運(yùn)行時常量池中的常量,基本來源于各個class文件中的常量池。

程序運(yùn)行時,除非手動向常量池中添加常量(比如調(diào)用intern方法),否則jvm不會自動添加常量到常量池。

以上所講僅涉及字符串常量池,實際上還有整型常量池、浮點型常量池等等,但都大同小異,只不過數(shù)值類型的常量池不可以手動添加常量,程序啟動時常量池中的常量就已經(jīng)確定了,比如整型常量池中的常量范圍:-128~127,只有這個范圍的數(shù)字可以用到常量池。

實踐

說了這么多理論,接下來讓我們觸摸一下真正的常量池。

前文提到過,class文件中存在一個靜態(tài)常量池,這個常量池是由編譯器生成的,用來存儲java源文件中的字面量(本文僅僅關(guān)注字面量),假設(shè)我們有如下java代碼:

 String s = "hi";

為了方便起見,就這么簡單,沒錯!將代碼編譯成class文件后,用winhex打開二進(jìn)制格式的class文件。如圖:

5.jpg

簡單講解一下class文件的結(jié)構(gòu),開頭的4個字節(jié)是class文件魔數(shù),用來標(biāo)識這是一個class文件,說白話點就是文件頭,既:CA FE BA BE。

緊接著4個字節(jié)是java的版本號,這里的版本號是34,因為筆者是用jdk8編譯的,版本號的高低和jdk版本的高低相對應(yīng),高版本可以兼容低版本,但低版本無法執(zhí)行高版本。所以,如果哪天讀者想知道別人的class文件是用什么jdk版本編譯的,就可以看這4個字節(jié)。

接下來就是常量池入口,入口處用2個字節(jié)標(biāo)識常量池常量數(shù)量,本例中數(shù)值為00 1A,翻譯成十進(jìn)制是26,也就是有25個常量,其中第0個常量是特殊值,所以只有25個常量。

常量池中存放了各種類型的常量,他們都有自己的類型,并且都有自己的存儲規(guī)范,本文只關(guān)注字符串常量,字符串常量以01開頭(1個字節(jié)),接著用2個字節(jié)記錄字符串長度,然后就是字符串實際內(nèi)容。本例中為:01 00 02 68 69。

接下來再說說運(yùn)行時常量池,由于運(yùn)行時常量池在方法區(qū)中,我們可以通過jvm參數(shù):-XX:PermSize、-XX:MaxPermSize來設(shè)置方法區(qū)大小,從而間接限制常量池大小。

假設(shè)jvm啟動參數(shù)為:-XX:PermSize=2M -XX:MaxPermSize=2M,然后運(yùn)行如下代碼:

//保持引用,防止自動垃圾回收
List<String> list = new ArrayList<String>();
        
int i = 0;
        
while(true){
    //通過intern方法向常量池中手動添加常量
    list.add(String.valueOf(i++).intern());
}

程序立刻會拋出:Exception in thread "main" java.lang.outOfMemoryError: PermGen space異常。PermGen space正是方法區(qū),足以說明常量池在方法區(qū)中。

在jdk8中,移除了方法區(qū),轉(zhuǎn)而用Metaspace區(qū)域替代,所以我們需要使用新的jvm參數(shù):-XX:MaxMetaspaceSize=2M,依然運(yùn)行如上代碼,拋出:java.lang.OutOfMemoryError: Metaspace異常。同理說明運(yùn)行時常量池是劃分在Metaspace區(qū)域中。具體關(guān)于Metaspace區(qū)域的知識,請讀者自行搜索。

更多java知識請關(guān)注java基礎(chǔ)教程欄目。

以上是java常量池圖文詳解的詳細(xì)內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級代碼編輯軟件(SublimeText3)

熱門話題

Laravel 教程
1601
29
PHP教程
1502
276
如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

要正確處理JDBC事務(wù),必須先關(guān)閉自動提交模式,再執(zhí)行多個操作,最后根據(jù)結(jié)果提交或回滾;1.調(diào)用conn.setAutoCommit(false)以開始事務(wù);2.執(zhí)行多個SQL操作,如INSERT和UPDATE;3.若所有操作成功則調(diào)用conn.commit(),若發(fā)生異常則調(diào)用conn.rollback()確保數(shù)據(jù)一致性;同時應(yīng)使用try-with-resources管理資源,妥善處理異常并關(guān)閉連接,避免連接泄漏;此外建議使用連接池、設(shè)置保存點實現(xiàn)部分回滾,并保持事務(wù)盡可能短以提升性能。

了解Java虛擬機(jī)(JVM)內(nèi)部 了解Java虛擬機(jī)(JVM)內(nèi)部 Aug 01, 2025 am 06:31 AM

TheJVMenablesJava’s"writeonce,runanywhere"capabilitybyexecutingbytecodethroughfourmaincomponents:1.TheClassLoaderSubsystemloads,links,andinitializes.classfilesusingbootstrap,extension,andapplicationclassloaders,ensuringsecureandlazyclassloa

如何使用Java的日歷? 如何使用Java的日歷? Aug 02, 2025 am 02:38 AM

使用java.time包中的類替代舊的Date和Calendar類;2.通過LocalDate、LocalDateTime和LocalTime獲取當(dāng)前日期時間;3.使用of()方法創(chuàng)建特定日期時間;4.利用plus/minus方法不可變地增減時間;5.使用ZonedDateTime和ZoneId處理時區(qū);6.通過DateTimeFormatter格式化和解析日期字符串;7.必要時通過Instant與舊日期類型兼容;現(xiàn)代Java中日期處理應(yīng)優(yōu)先使用java.timeAPI,它提供了清晰、不可變且線

比較Java框架:Spring Boot vs Quarkus vs Micronaut 比較Java框架:Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

前形式攝取,quarkusandmicronautleaddueTocile timeProcessingandGraalvSupport,withquarkusoftenpernperforminglightbetterine nosserless notelless centarios.2。

了解網(wǎng)絡(luò)端口和防火墻 了解網(wǎng)絡(luò)端口和防火墻 Aug 01, 2025 am 06:40 AM

NetworkPortSandFireWallsworkTogetHertoEnableCommunication whereSeringSecurity.1.NetWorkPortSareVirtualendPointSnumbered0-655 35,with-Well-with-Newonportslike80(HTTP),443(https),22(SSH)和25(smtp)sindiessingspefificservices.2.portsoperateervertcp(可靠,c

垃圾收集如何在Java工作? 垃圾收集如何在Java工作? Aug 02, 2025 pm 01:55 PM

Java的垃圾回收(GC)是自動管理內(nèi)存的機(jī)制,通過回收不可達(dá)對象釋放堆內(nèi)存,減少內(nèi)存泄漏風(fēng)險。1.GC從根對象(如棧變量、活動線程、靜態(tài)字段等)出發(fā)判斷對象可達(dá)性,無法到達(dá)的對象被標(biāo)記為垃圾。2.基于標(biāo)記-清除算法,標(biāo)記所有可達(dá)對象,清除未標(biāo)記對象。3.采用分代收集策略:新生代(Eden、S0、S1)頻繁執(zhí)行MinorGC;老年代執(zhí)行較少但耗時較長的MajorGC;Metaspace存儲類元數(shù)據(jù)。4.JVM提供多種GC器:SerialGC適用于小型應(yīng)用;ParallelGC提升吞吐量;CMS降

比較Java構(gòu)建工具:Maven vs. Gradle 比較Java構(gòu)建工具:Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

Gradleisthebetterchoiceformostnewprojectsduetoitssuperiorflexibility,performance,andmoderntoolingsupport.1.Gradle’sGroovy/KotlinDSLismoreconciseandexpressivethanMaven’sverboseXML.2.GradleoutperformsMaveninbuildspeedwithincrementalcompilation,buildcac

以身作則,解釋說明 以身作則,解釋說明 Aug 02, 2025 am 06:26 AM

defer用于在函數(shù)返回前執(zhí)行指定操作,如清理資源;參數(shù)在defer時立即求值,函數(shù)按后進(jìn)先出(LIFO)順序執(zhí)行;1.多個defer按聲明逆序執(zhí)行;2.常用于文件關(guān)閉等安全清理;3.可修改命名返回值;4.即使發(fā)生panic也會執(zhí)行,適合用于recover;5.避免在循環(huán)中濫用defer,防止資源泄漏;正確使用可提升代碼安全性和可讀性。

See all articles