深入了解JVM(Java虛擬機(jī))內(nèi)存結(jié)構(gòu)
JVM內(nèi)存結(jié)構(gòu)
Java虛擬機(jī)的內(nèi)存結(jié)構(gòu)分為5個(gè)部分:
- 程序計(jì)數(shù)器
- Java 虛擬機(jī)棧
- 本地方法棧
- 堆
- 方法區(qū)

JDK1.7與1.8的區(qū)別:
- 1.7中有有一個(gè)永久代,存儲(chǔ)的是類信息、靜態(tài)變量、常量、編譯后的代碼
- 1.8移除了永久代,把數(shù)據(jù)存儲(chǔ)到了本地內(nèi)存的元空間中,防止內(nèi)存溢出
程序計(jì)數(shù)器(PC寄存器)
程序計(jì)數(shù)器定義
線程私有的,每個(gè)線程一份,內(nèi)部保存的字節(jié)碼的行號(hào)。用于記錄正在執(zhí)行的字節(jié)碼指令的地址。
程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,是當(dāng)前線程正在執(zhí)行的那條字節(jié)碼指令的地址。若當(dāng)前線程正在執(zhí)行的是一個(gè)本地方法,那么此時(shí)程序計(jì)數(shù)器為 Undefined 。
javap -v xx.class 打印堆棧大小,局部變量的數(shù)量和方法的參數(shù)。

程序計(jì)數(shù)器的作用
- 字節(jié)碼解釋器通過(guò)改變程序計(jì)數(shù)器來(lái)依次讀取指令,從而實(shí)現(xiàn)代碼的流程控制。
- 在多線程情況下,程序計(jì)數(shù)器記錄的是當(dāng)前線程執(zhí)行的位置,從而當(dāng)線程切換回來(lái)時(shí),就知道上次線程執(zhí)行到哪了。
程序計(jì)數(shù)器的特點(diǎn)
- 是一塊較小的內(nèi)存空間。
- 線程私有,每條線程都有自己的程序計(jì)數(shù)器。
- 生命周期:隨著線程的創(chuàng)建而創(chuàng)建,隨著線程的結(jié)束而銷毀。
- 是唯一一個(gè)不會(huì)出現(xiàn)
OutOfMemoryError的內(nèi)存區(qū)域。
Java虛擬機(jī)棧
Java虛擬機(jī)棧的定義
Java 虛擬機(jī)棧是描述 Java 方法運(yùn)行過(guò)程的內(nèi)存模型。
Java Virtual machine Stacks (java 虛擬機(jī)棧)
- 每個(gè)線程運(yùn)行時(shí)所需要的內(nèi)存,稱為虛擬機(jī)棧,先進(jìn)后出
- 每個(gè)棧由多個(gè)棧幀(frame)組成,對(duì)應(yīng)著每次方法調(diào)用時(shí)所占用的內(nèi)存
- 每個(gè)線程只能有一個(gè)活動(dòng)棧幀,對(duì)應(yīng)著當(dāng)前正在執(zhí)行的那個(gè)方法

垃圾回收是否涉及棧內(nèi)存?
垃圾回收主要指就是堆內(nèi)存,當(dāng)棧幀彈棧以后,內(nèi)存就會(huì)釋放
棧內(nèi)存分配越大越好嗎?
未必,默認(rèn)的棧內(nèi)存通常為1024k
棧幀過(guò)大會(huì)導(dǎo)致線程數(shù)變少,例如,機(jī)器總內(nèi)存為512m,目前能活動(dòng)的線程數(shù)則為512個(gè),如果把棧內(nèi)存改為2048k,那么能活動(dòng)的棧幀就會(huì)減半
方法內(nèi)的局部變量是否線程安全?
- 如果方法內(nèi)局部變量沒(méi)有逃離方法的作用范圍,它是線程安全的
- 如果是局部變量引用了對(duì)象,并逃離方法的作用范圍,需要考慮線程安全

虛擬機(jī)棧的組成
Java 虛擬機(jī)棧會(huì)為每一個(gè)即將運(yùn)行的 Java 方法創(chuàng)建一塊叫做“棧幀”的區(qū)域,用于存放該方法運(yùn)行過(guò)程中的一些信息,如:
- 局部變量表
- 操作數(shù)棧
- 動(dòng)態(tài)鏈接
- 方法出口信息
- ......

壓棧出棧過(guò)程
當(dāng)方法運(yùn)行過(guò)程中需要?jiǎng)?chuàng)建局部變量時(shí),就將局部變量的值存入棧幀中的局部變量表中。
Java 虛擬機(jī)棧的棧頂?shù)臈钱?dāng)前正在執(zhí)行的活動(dòng)棧,也就是當(dāng)前正在執(zhí)行的方法,PC 寄存器也會(huì)指向這個(gè)地址。只有這個(gè)活動(dòng)的棧幀的本地變量可以被操作數(shù)棧使用,當(dāng)在這個(gè)棧幀中調(diào)用另一個(gè)方法,與之對(duì)應(yīng)的棧幀又會(huì)被創(chuàng)建,新創(chuàng)建的棧幀壓入棧頂,變?yōu)楫?dāng)前的活動(dòng)棧幀。
方法結(jié)束后,當(dāng)前棧幀被移出,棧幀的返回值變成新的活動(dòng)棧幀中操作數(shù)棧的一個(gè)操作數(shù)。如果沒(méi)有返回值,那么新的活動(dòng)棧幀中操作數(shù)棧的操作數(shù)沒(méi)有變化。
由于 Java 虛擬機(jī)棧是與線程對(duì)應(yīng)的,數(shù)據(jù)不是線程共享的(也就是線程私有的),因此不用關(guān)心數(shù)據(jù)一致性問(wèn)題,也不會(huì)存在同步鎖的問(wèn)題。
局部變量表
定義為一個(gè)數(shù)字?jǐn)?shù)組,主要用于存儲(chǔ)方法參數(shù)、定義在方法體內(nèi)部的局部變量,數(shù)據(jù)類型包括各類基本數(shù)據(jù)類型,對(duì)象引用,以及 return address 類型。
局部變量表容量大小是在編譯期確定下來(lái)的。最基本的存儲(chǔ)單元是 slot,32 位占用一個(gè) slot,64 位類型(long 和 double)占用兩個(gè) slot。
對(duì)于 slot 的理解:
- JVM 虛擬機(jī)會(huì)為局部變量表中的每個(gè) slot 都分配一個(gè)訪問(wèn)索引,通過(guò)這個(gè)索引即可成功訪問(wèn)到局部變量表中指定的局部變量值。
- 如果當(dāng)前幀是由構(gòu)造方法或者實(shí)例方法創(chuàng)建的,那么該對(duì)象引用 this,會(huì)存放在 index 為 0 的 slot 處,其余的參數(shù)表順序繼續(xù)排列。
- 棧幀中的局部變量表中的槽位是可以重復(fù)的,如果一個(gè)局部變量過(guò)了其作用域,那么其作用域之后申明的新的局部變量就有可能會(huì)復(fù)用過(guò)期局部變量的槽位,從而達(dá)到節(jié)省資源的目的。
在棧幀中,與性能調(diào)優(yōu)關(guān)系最密切的部分,就是局部變量表,方法執(zhí)行時(shí),虛擬機(jī)使用局部變量表完成方法的傳遞局部變量表中的變量也是重要的垃圾回收根節(jié)點(diǎn),只要被局部變量表中直接或間接引用的對(duì)象都不會(huì)被回收。
操作數(shù)棧
- 棧頂緩存技術(shù):由于操作數(shù)是存儲(chǔ)在內(nèi)存中,頻繁的進(jìn)行內(nèi)存讀寫操作影響執(zhí)行速度,將棧頂元素全部緩存到物理 CPU 的寄存器中,以此降低對(duì)內(nèi)存的讀寫次數(shù),提升執(zhí)行引擎的執(zhí)行效率。
- 每一個(gè)操作數(shù)棧會(huì)擁有一個(gè)明確的棧深度,用于存儲(chǔ)數(shù)值,最大深度在編譯期就定義好。32bit 類型占用一個(gè)棧單位深度,64bit 類型占用兩個(gè)棧單位深度操作數(shù)棧。
- 并非采用訪問(wèn)索引方式進(jìn)行數(shù)據(jù)訪問(wèn),而是只能通過(guò)標(biāo)準(zhǔn)的入棧、出棧操作完成一次數(shù)據(jù)訪問(wèn)。
本地方法棧
本地方法棧的定義
本地方法棧是為 JVM 運(yùn)行 Native 方法準(zhǔn)備的空間,由于很多 Native 方法都是用 C 語(yǔ)言實(shí)現(xiàn)的,所以它通常又叫 C 棧。它與 Java 虛擬機(jī)棧實(shí)現(xiàn)的功能類似,只不過(guò)本地方法棧是描述本地方法運(yùn)行過(guò)程的內(nèi)存模型。
棧幀變化過(guò)程
本地方法被執(zhí)行時(shí),在本地方法棧也會(huì)創(chuàng)建一塊棧幀,用于存放該方法的局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口信息等。
方法執(zhí)行結(jié)束后,相應(yīng)的棧幀也會(huì)出棧,并釋放內(nèi)存空間。也會(huì)拋出 StackOverFlowError 和 OutOfMemoryError 異常。
如果 Java 虛擬機(jī)本身不支持 Native 方法,或是本身不依賴于傳統(tǒng)棧,那么可以不提供本地方法棧。如果支持本地方法棧,那么這個(gè)棧一般會(huì)在線程創(chuàng)建的時(shí)候按線程分配。
Java堆
堆的定義
線程共享的區(qū)域:主要用來(lái)保存對(duì)象實(shí)例,數(shù)組等,當(dāng)堆中沒(méi)有內(nèi)存空間可分配給實(shí)例,也無(wú)法再擴(kuò)展時(shí),則拋出OutOfMemoryError異常。

堆是用來(lái)存放對(duì)象的內(nèi)存空間, 幾乎 所有的對(duì)象都存儲(chǔ)在堆中。

堆的特點(diǎn)
- 線程共享,整個(gè) Java 虛擬機(jī)只有一個(gè)堆,所有的線程都訪問(wèn)同一個(gè)堆。而程序計(jì)數(shù)器、Java 虛擬機(jī)棧、本地方法棧都是一個(gè)線程對(duì)應(yīng)一個(gè)。
- 在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。
- 是垃圾回收的主要場(chǎng)所。
- 堆可分為新生代(Eden 區(qū):
From Survior,To Survivor)、老年代。 - Java 虛擬機(jī)規(guī)范規(guī)定,堆可以處于物理上不連續(xù)的內(nèi)存空間中,但在邏輯上它應(yīng)該被視為連續(xù)的。
- 關(guān)于 Survivor s0,s1 區(qū): 復(fù)制之后有交換,誰(shuí)空誰(shuí)是 to。
不同的區(qū)域存放不同生命周期的對(duì)象,這樣可以根據(jù)不同的區(qū)域使用不同的垃圾回收算法,更具有針對(duì)性。
堆的大小既可以固定也可以擴(kuò)展,但對(duì)于主流的虛擬機(jī),堆的大小是可擴(kuò)展的,因此當(dāng)線程請(qǐng)求分配內(nèi)存,但堆已滿,且內(nèi)存已無(wú)法再擴(kuò)展時(shí),就拋出 OutOfMemoryError 異常。
Java 堆所使用的內(nèi)存不需要保證是連續(xù)的。而由于堆是被所有線程共享的,所以對(duì)它的訪問(wèn)需要注意同步問(wèn)題,方法和對(duì)應(yīng)的屬性都需要保證一致性。
新生代與老年代
- 老年代比新生代生命周期長(zhǎng)。
- 新生代與老年代空間默認(rèn)比例
1:2:JVM 調(diào)參數(shù),XX:NewRatio=2,表示新生代占 1,老年代占 2,新生代占整個(gè)堆的 1/3。 - HotSpot 中,Eden 空間和另外兩個(gè) Survivor 空間缺省所占的比例是:
8:1:1。 - 幾乎所有的 Java 對(duì)象都是在 Eden 區(qū)被 new 出來(lái)的,Eden 放不了的大對(duì)象,就直接進(jìn)入老年代了。
對(duì)象分配過(guò)程
- new 的對(duì)象先放在 Eden 區(qū),大小有限制
- 如果創(chuàng)建新對(duì)象時(shí),Eden 空間填滿了,就會(huì)觸發(fā) Minor GC,將 Eden 不再被其他對(duì)象引用的對(duì)象進(jìn)行銷毀,再加載新的對(duì)象放到 Eden 區(qū),特別注意的是 Survivor 區(qū)滿了是不會(huì)觸發(fā) Minor GC 的,而是 Eden 空間填滿了,Minor GC 才順便清理 Survivor 區(qū)
- 將 Eden 中剩余的對(duì)象移到 Survivor0 區(qū)
- 再次觸發(fā)垃圾回收,此時(shí)上次 Survivor 下來(lái)的,放在 Survivor0 區(qū)的,如果沒(méi)有回收,就會(huì)放到 Survivor1 區(qū)
- 再次經(jīng)歷垃圾回收,又會(huì)將幸存者重新放回 Survivor0 區(qū),依次類推
- 默認(rèn)是 15 次的循環(huán),超過(guò) 15 次,則會(huì)將幸存者區(qū)幸存下來(lái)的轉(zhuǎn)去老年區(qū) jvm 參數(shù)設(shè)置次數(shù) : -XX:MaxTenuringThreshold=N 進(jìn)行設(shè)置
- 頻繁在新生區(qū)收集,很少在養(yǎng)老區(qū)收集,幾乎不在永久區(qū)/元空間搜集
Full GC /Major GC 觸發(fā)條件
- 顯示調(diào)用
System.gc(),老年代的空間不夠,方法區(qū)的空間不夠等都會(huì)觸發(fā) Full GC,同時(shí)對(duì)新生代和老年代回收,F(xiàn)Ull GC 的 STW 的時(shí)間最長(zhǎng),應(yīng)該要避免 - 在出現(xiàn) Major GC 之前,會(huì)先觸發(fā) Minor GC,如果老年代的空間還是不夠就會(huì)觸發(fā) Major GC,STW 的時(shí)間長(zhǎng)于 Minor GC
逃逸分析
標(biāo)量替換
- 標(biāo)量不可在分解的量,java 的基本數(shù)據(jù)類型就是標(biāo)量,標(biāo)量的對(duì)立就是可以被進(jìn)一步分解的量,而這種量稱之為聚合量。而在 JAVA 中對(duì)象就是可以被進(jìn)一步分解的聚合量
- 替換過(guò)程,通過(guò)逃逸分析確定該對(duì)象不會(huì)被外部訪問(wèn),并且對(duì)象可以被進(jìn)一步分解時(shí),JVM 不會(huì)創(chuàng)建該對(duì)象,而會(huì)將該對(duì)象成員變量分解若干個(gè)被這個(gè)方法使用的成員變量所代替。這些代替的成員變量在棧幀或寄存器上分配空間。
- 對(duì)象和數(shù)組并非都是在堆上分配內(nèi)存的
- 《深入理解 Java 虛擬機(jī)中》關(guān)于 Java 堆內(nèi)存有這樣一段描述:隨著 JIT 編譯期的發(fā)展與逃逸分析技術(shù)逐漸成熟,
棧上分配,標(biāo)量替換優(yōu)化技術(shù)將會(huì)導(dǎo)致一些變化,所有的對(duì)象都分配到堆上也漸漸變得不那么"絕對(duì)"了。 - 這是一種可以有效減少 Java 內(nèi)存堆分配壓力的分析算法,通過(guò)逃逸分析,Java Hotspot 編譯器能夠分析出一個(gè)新的對(duì)象的引用的使用范圍從而決定是否要將這個(gè)對(duì)象分配到堆上。
- 當(dāng)一個(gè)對(duì)象在方法中被定義后,它可能被外部方法所引用,如作為調(diào)用參數(shù)傳遞到其他地方中,稱為
方法逃逸。 - 再如賦值給類變量或可以在其他線程中訪問(wèn)的實(shí)例變量,稱為
線程逃逸 - 使用逃逸分析,編譯器可以對(duì)代碼做如下優(yōu)化:
- 同步省略:如果一個(gè)對(duì)象被發(fā)現(xiàn)只能從一個(gè)線程被訪問(wèn)到,那么對(duì)于這個(gè)對(duì)象的操作可以不考慮同步。
- 將堆分配轉(zhuǎn)化為棧分配:如果一個(gè)對(duì)象在子程序中被分配,要使指向該對(duì)象的指針永遠(yuǎn)不會(huì)逃逸,對(duì)象可能是棧分配的候選,而不是堆分配。
- 分離對(duì)象或標(biāo)量替換:有的對(duì)象可能不需要作為一個(gè)連續(xù)的內(nèi)存結(jié)構(gòu)存在也可以被訪問(wèn)到,那么對(duì)象的部分(或全部)可以不存儲(chǔ)在內(nèi)存,而是存儲(chǔ)在 CPU 寄存器中。
public?static?StringBuffer?createStringBuffer(String?s1,?String?s2)?{
????StringBuffer?s?=?new?StringBuffer();
????s.append(s1);
????s.append(s2);
????return?s;
}s 是一個(gè)方法內(nèi)部變量,上邊的代碼中直接將 s 返回,這個(gè) StringBuffer 的對(duì)象有可能被其他方法所改變,導(dǎo)致它的作用域就不只是在方法內(nèi)部,即使它是一個(gè)局部變量,但還是逃逸到了方法外部,稱為 方法逃逸 。
還有可能被外部線程訪問(wèn)到,譬如賦值給類變量或可以在其他線程中訪問(wèn)的實(shí)例變量,稱為 線程逃逸 。
- 在編譯期間,如果 JIT 經(jīng)過(guò)逃逸分析,發(fā)現(xiàn)有些對(duì)象沒(méi)有逃逸出方法,那么有可能堆內(nèi)存分配會(huì)被優(yōu)化成棧內(nèi)存分配。
- jvm 參數(shù)設(shè)置,
-XX:+DoEscapeAnalysis:開(kāi)啟逃逸分析 ,-XX:-DoEscapeAnalysis: 關(guān)閉逃逸分析 - 從 jdk 1.7 開(kāi)始已經(jīng)默認(rèn)開(kāi)始逃逸分析。
TLAB
- TLAB 的全稱是 Thread Local Allocation Buffer,即線程本地分配緩存區(qū),是屬于 Eden 區(qū)的,這是一個(gè)線程專用的內(nèi)存分配區(qū)域,線程私有,默認(rèn)開(kāi)啟的(當(dāng)然也不是絕對(duì)的,也要看哪種類型的虛擬機(jī))
- 堆是全局共享的,在同一時(shí)間,可能會(huì)有多個(gè)線程在堆上申請(qǐng)空間,但每次的對(duì)象分配需要同步的進(jìn)行(虛擬機(jī)采用 CAS 配上失敗重試的方式保證更新操作的原子性)但是效率卻有點(diǎn)下降
- 所以用 TLAB 來(lái)避免多線程沖突,在給對(duì)象分配內(nèi)存時(shí),每個(gè)線程使用自己的 TLAB,這樣可以使得線程同步,提高了對(duì)象分配的效率
- 當(dāng)然并不是所有的對(duì)象都可以在 TLAB 中分配內(nèi)存成功,如果失敗了就會(huì)使用加鎖的機(jī)制來(lái)保持操作的原子性
-XX:+UseTLAB使用 TLAB,-XX:+TLABSize設(shè)置 TLAB 大小
方法區(qū)
Java 虛擬機(jī)規(guī)范中定義方法區(qū)是堆的一個(gè)邏輯部分。方法區(qū)存放以下信息:
- 已經(jīng)被虛擬機(jī)加載的類信息
- 常量
- 靜態(tài)變量
- 即時(shí)編譯器編譯后的代碼
方法區(qū)的簡(jiǎn)單理解:
- 方法區(qū)(Method Area)是各個(gè)線程共享的內(nèi)存區(qū)域
- 主要存儲(chǔ)類的信息、運(yùn)行時(shí)常量池
- 虛擬機(jī)啟動(dòng)的時(shí)候創(chuàng)建,關(guān)閉虛擬機(jī)時(shí)釋放
- 如果方法區(qū)域中的內(nèi)存無(wú)法滿足分配請(qǐng)求,則會(huì)拋出OutOfMemoryError: Metaspace

方法區(qū)的特點(diǎn)
- 線程共享。 方法區(qū)是堆的一個(gè)邏輯部分,因此和堆一樣,都是線程共享的。整個(gè)虛擬機(jī)中只有一個(gè)方法區(qū)。
- 永久代。 方法區(qū)中的信息一般需要長(zhǎng)期存在,而且它又是堆的邏輯分區(qū),因此用堆的劃分方法,把方法區(qū)稱為“永久代”。
- 內(nèi)存回收效率低。 方法區(qū)中的信息一般需要長(zhǎng)期存在,回收一遍之后可能只有少量信息無(wú)效。主要回收目標(biāo)是:對(duì)常量池的回收;對(duì)類型的卸載。
- Java 虛擬機(jī)規(guī)范對(duì)方法區(qū)的要求比較寬松。 和堆一樣,允許固定大小,也允許動(dòng)態(tài)擴(kuò)展,還允許不實(shí)現(xiàn)垃圾回收。
運(yùn)行時(shí)常量池
常量池可以看作是一張表,虛擬機(jī)指令根據(jù)這張常量表找到要執(zhí)行的類名、方法名、參數(shù)類型、字面量等信息。
常量池是 *.class 文件中的,當(dāng)該類被加載,它的常量池信息就會(huì)放入運(yùn)行時(shí)常量池,并把里面的符號(hào)地址變?yōu)檎鎸?shí)地址
查看字節(jié)碼結(jié)構(gòu)(類的基本信息、常量池、方法定義)
javap -v Application.class

直接內(nèi)存
直接內(nèi)存:并不屬于JVM中的內(nèi)存結(jié)構(gòu),不由JVM進(jìn)行管理。是虛擬機(jī)的系統(tǒng)內(nèi)存,常見(jiàn)于 NIO 操作時(shí),用于數(shù)據(jù)緩沖區(qū),它分配回收成本較高,但讀寫性能高。
直接內(nèi)存的大小不受 Java 虛擬機(jī)控制,但既然是內(nèi)存,當(dāng)內(nèi)存不足時(shí)就會(huì)拋出 OutOfMemoryError 異常。
常規(guī)IO的數(shù)據(jù)拷貝流程

NIO數(shù)據(jù)拷貝流程

直接內(nèi)存與堆內(nèi)存比較
- 直接內(nèi)存申請(qǐng)空間耗費(fèi)更高的性能
- 直接內(nèi)存讀取 IO 的性能要優(yōu)于普通的堆內(nèi)存
- 直接內(nèi)存作用鏈: 本地 IO -> 直接內(nèi)存 -> 本地 IO
- 堆內(nèi)存作用鏈:本地 IO -> 直接內(nèi)存 -> 非直接內(nèi)存 -> 直接內(nèi)存 -> 本地 IO
服務(wù)器管理員在配置虛擬機(jī)參數(shù)時(shí),會(huì)根據(jù)實(shí)際內(nèi)存設(shè)置 -Xmx 等參數(shù)信息,但經(jīng)常忽略直接內(nèi)存,使得各個(gè)內(nèi)存區(qū)域總和大于物理內(nèi)存限制,從而導(dǎo)致動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn) OutOfMemoryError 異常。
以上就是深入了解JVM(Java虛擬機(jī))內(nèi)存結(jié)構(gòu)的詳細(xì)內(nèi)容,更多關(guān)于JVM內(nèi)存結(jié)構(gòu)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Netty分布式NioEventLoop任務(wù)隊(duì)列執(zhí)行源碼分析
這篇文章主要為大家介紹了Netty分布式NioEventLoop任務(wù)隊(duì)列執(zhí)行源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
Maven項(xiàng)src/main/java目錄下配置文件無(wú)法被導(dǎo)出或者生效的問(wèn)題和處理方案
這篇文章主要介紹了Maven項(xiàng)src/main/java目錄下配置文件無(wú)法被導(dǎo)出或者生效的問(wèn)題和處理方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Spring @Profile注解實(shí)現(xiàn)多環(huán)境配置
這篇文章主要介紹了Spring @Profile注解實(shí)現(xiàn)多環(huán)境配置,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Java中final關(guān)鍵字的使用與注意總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中final關(guān)鍵字的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器
本篇文章主要介紹了詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
為什么SpringMVC中請(qǐng)求的body不支持多次讀取
這篇文章主要介紹了為什么SpringMVC中請(qǐng)求的body不支持多次讀取,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
IDEA導(dǎo)入外部項(xiàng)目報(bào)Error:java: 無(wú)效的目標(biāo)發(fā)行版: 11的解決方法
這篇文章主要介紹了IDEA導(dǎo)入外部項(xiàng)目報(bào)Error:java: 無(wú)效的目標(biāo)發(fā)行版: 11,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
Java通過(guò)匿名類來(lái)實(shí)現(xiàn)回調(diào)函數(shù)實(shí)例總結(jié)
這篇文章主要介紹了Java通過(guò)匿名類來(lái)實(shí)現(xiàn)回調(diào)函數(shù)的例子,回調(diào)函數(shù)就是一種函數(shù)簽名(若干個(gè)輸入?yún)?shù)、一個(gè)輸出參數(shù))的規(guī)范,java雖不存在函數(shù)聲明,但是java可以用接口來(lái)強(qiáng)制規(guī)范。具體操作步驟大家可查看下文的詳細(xì)講解,感興趣的小伙伴們可以參考一下。2017-08-08

