成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

看了這篇你還不懂JVM 中的類加載機(jī)制?

云計(jì)算 虛擬化
驗(yàn)證是連接階段的第一個(gè)步驟,驗(yàn)證的目的是為了確保`.class`文件中的字節(jié)流所包含的信息是符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害到虛擬機(jī)自身的安全的。

[[326861]]

開(kāi)門(mén)見(jiàn)山

首先引入一道面試題

 

看了這篇你還不懂JVM 中的類加載機(jī)制?

 

  • 錯(cuò)誤答案:count1=1;count2=1
  • 正確答案:count1=1;count2=0

為神馬?為神馬?這要從java的類加載時(shí)機(jī)說(shuō)起。

本來(lái)是準(zhǔn)備把分析結(jié)果寫(xiě)在最下面的但是怕大家沒(méi)有耐心看到最后我這邊先大概分析下,如果看不懂下面的分析。真心建議大家能看到最后,文章不算長(zhǎng)。

  1. `Single single = Single.getInstance();`調(diào)用了類的`Single`調(diào)用了類的靜態(tài)方法,觸發(fā)類的初始化
  2. 類加載的時(shí)候在準(zhǔn)備過(guò)程中為類的靜態(tài)變量分配內(nèi)存并初始化默認(rèn)值 `single=null count1=0,count2=0`
  3. 類初始化化,為類的靜態(tài)變量賦值和執(zhí)行靜態(tài)代碼快。`single`賦值為`new Single()`調(diào)用類的構(gòu)造方法
  4. 調(diào)用類的構(gòu)造方法后`count=1;count2=1`
  5. 繼續(xù)為`count1`與`count2`賦值,此時(shí)`count1`沒(méi)有賦值操作,所有`count1`為1,但是`count2`執(zhí)行賦值操作就變?yōu)?

類的加載時(shí)機(jī)

類從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,直到卸載出內(nèi)存為止,它的整個(gè)生命周期包括了:加載、驗(yàn)證、準(zhǔn)備、解析、初始化、使用和卸載這7個(gè)階段。其中,驗(yàn)證、準(zhǔn)備和解析這三個(gè)部分統(tǒng)稱為連接(linking)。

 

看了這篇你還不懂JVM 中的類加載機(jī)制?

 

其中加載、驗(yàn)證、準(zhǔn)備、初始化和卸載五個(gè)步驟的順序都是確定的,解析階段在某些情況下有可能發(fā)生在初始化之后,這是為了支持 Java 語(yǔ)言的運(yùn)行期綁定的特性。

何時(shí)開(kāi)始類的初始化

  1. 創(chuàng)建類的實(shí)例
  2. 訪問(wèn)類的靜態(tài)變量(除常量【被final修辭的靜態(tài)變量】原因:常量一種特殊的變量,因?yàn)榫幾g器把他們當(dāng)作值(value)而不是域(field)來(lái)對(duì)待。如果你的代碼中用到了常變量(`constant variable`),編譯器并不會(huì)生成字節(jié)碼來(lái)從對(duì)象中載入域的值,而是直接把這個(gè)值插入到字節(jié)碼中。這是一種很有用的優(yōu)化,但是如果你需要改變final域的值那么每一塊用到那個(gè)域的代碼都需要重新編譯。
  3. 訪問(wèn)類的靜態(tài)方法
  4. 反射如(`Class.forName("my.xyz.Test")`)
  5. 當(dāng)初始化一個(gè)類時(shí),發(fā)現(xiàn)其父類還未初始化,則先出發(fā)父類的初始化
  6. 虛擬機(jī)啟動(dòng)時(shí),定義了main()方法的那個(gè)類先初始化
  • 主動(dòng)引用:上面這些種行為稱為對(duì)一個(gè)類的的主動(dòng)引用,會(huì)觸發(fā)類的初始化
  • 被動(dòng)引用:除上面五種主動(dòng)引用之外,其他引用類的方式都不會(huì)觸發(fā)類的初始化,稱為類的被動(dòng)引用

接口的加載過(guò)程與類的加載過(guò)程稍有不同。接口中不能使用`static{}`塊。當(dāng)一個(gè)接口在初始化時(shí),并不要求其父接口全部都完成了初始化,只有真正在使用到父接口時(shí)(例如引用接口中定義的常量)才會(huì)初始化。

被動(dòng)引用例子

示例一

對(duì)于靜態(tài)字段,只有直接定義這個(gè)字段的類會(huì)被初始化,如果是通過(guò)子類引用父類的字段,父類會(huì)被初始化,子類不一定會(huì)被初始化,子類會(huì)不會(huì)被初始化 JVM 虛擬機(jī)規(guī)范并沒(méi)有明確規(guī)定,取決于虛擬機(jī)的具體實(shí)現(xiàn)

 

看了這篇你還不懂JVM 中的類加載機(jī)制?

 

上面代碼運(yùn)行之后輸出結(jié)果如下所示

  1. SuperClass init! 
  2. The value is 24 

示例二

 

看了這篇你還不懂JVM 中的類加載機(jī)制?

 

上面代碼運(yùn)行之后,并不會(huì)輸出 “SubClass init!“,因?yàn)樵谏厦鍰emo#main()方法中,并沒(méi)有初始化SubClass類,而是初始化了一個(gè)SubClass[]數(shù)組類,SubClass[]數(shù)組類代表了一個(gè)元素類型為SubClass的一維數(shù)組,繼承自O(shè)bject類,由newarray字節(jié)碼創(chuàng)建。

示例三

 

看了這篇你還不懂JVM 中的類加載機(jī)制?

 

上面代碼運(yùn)行之后也并不會(huì)輸出”Constant init!“,因?yàn)檫@涉及到一個(gè)概念 —- “常量傳播優(yōu)化”。雖然在代碼中Demo類引用了Constant類中的常量VALUE,但是在編譯階段,會(huì)將VALUE的實(shí)際值”Hello World!“放到Demo類中的常量池中,Demo類每次使用”Hello World!“常量的時(shí)候都會(huì)從自己的常量池中去找。Demo類不會(huì)持有Constant類的符號(hào)引用,所以Constant類也并不會(huì)被初始化。

類的加載過(guò)程

加載

在加載階段有三個(gè)步驟:

  1. 通過(guò)一個(gè)類的全限定名獲取定義此類的二進(jìn)制字節(jié)流
  2. 將二進(jìn)制字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)中的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
  3. 在內(nèi)存中生成一個(gè)代表此類的`java.lang.Class`的對(duì)象,作為方法區(qū)這些數(shù)據(jù)的訪問(wèn)入口

在這個(gè)階段,有兩點(diǎn)需要注意:

  1. 并沒(méi)有規(guī)定從哪里獲取二進(jìn)制字節(jié)流。我們可以從`.class`靜態(tài)存儲(chǔ)文件中獲取,也可以從`zip、jar`等包中讀取,可以從數(shù)據(jù)庫(kù)中讀取,也可以從網(wǎng)絡(luò)中獲取,甚至我們自己可以在運(yùn)行時(shí)自動(dòng)生成。
  2. 在內(nèi)存中實(shí)例化一個(gè)代表此類的`java.lang.Class`對(duì)象之后,并沒(méi)有規(guī)定此`Class`對(duì)象是方法`Java`堆中的,有些虛擬機(jī)就會(huì)將`Class`對(duì)象放到方法區(qū)中,比如`HotSpot`。

驗(yàn)證

驗(yàn)證是連接階段的第一個(gè)步驟,驗(yàn)證的目的是為了確保`.class`文件中的字節(jié)流所包含的信息是符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害到虛擬機(jī)自身的安全的。

`Java`語(yǔ)言本身是相對(duì)安全的語(yǔ)言,使用Java編碼是無(wú)法做到如訪問(wèn)數(shù)組邊界以外的數(shù)據(jù)、將一個(gè)對(duì)象轉(zhuǎn)型為它并未實(shí)現(xiàn)的類型等,如果這樣做了,編譯器將拒絕編譯。但是,`Class`文件并不一定是由`Java`源碼編譯而來(lái),可以使用任何途徑,包括用十六進(jìn)制編輯器(如`UltraEdit`)直接編寫(xiě)。如果直接編寫(xiě)了有害的“代碼”(字節(jié)流),而虛擬機(jī)在加載該Class時(shí)不進(jìn)行檢查的話,就有可能危害到虛擬機(jī)或程序的安全。

  1. 不同的虛擬機(jī),對(duì)類驗(yàn)證的實(shí)現(xiàn)可能有所不同,但大致都會(huì)完成下面四個(gè)階段的驗(yàn)證:文件格式驗(yàn)證、元數(shù)據(jù)驗(yàn)證、字節(jié)碼驗(yàn)證和符號(hào)引用驗(yàn)證。文件格式驗(yàn)證,是要驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當(dāng)前版本的虛擬機(jī)處理。如驗(yàn)證魔數(shù)是否0xCAFEBABE;主、次版本號(hào)是否正在當(dāng)前虛擬機(jī)處理范圍之內(nèi);常量池的常量中是否有不被支持的常量類型……該驗(yàn)證階段的主要目的是保證輸入的字節(jié)流能正確地解析并存儲(chǔ)于方法區(qū)中,經(jīng)過(guò)這個(gè)階段的驗(yàn)證后,字節(jié)流才會(huì)進(jìn)入內(nèi)存的方法區(qū)中存儲(chǔ),所以后面的三個(gè)驗(yàn)證階段都是基于方法區(qū)的存儲(chǔ)結(jié)構(gòu)進(jìn)行的。
  2. 元數(shù)據(jù)驗(yàn)證,是對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,以保證其描述的信息符合Java語(yǔ)言規(guī)范的要求。可能包括的驗(yàn)證如:這個(gè)類是否有父類;這個(gè)類的父類是否繼承了不允許被繼承的類;如果這個(gè)類不是抽象類,是否實(shí)現(xiàn)了其父類或接口中要求實(shí)現(xiàn)的所有方法……
  3. 字節(jié)碼驗(yàn)證,主要工作是進(jìn)行數(shù)據(jù)流和控制流分析,保證被校驗(yàn)類的方法在運(yùn)行時(shí)不會(huì)做出危害虛擬機(jī)安全的行為。如果一個(gè)類方法體的字節(jié)碼沒(méi)有通過(guò)字節(jié)碼驗(yàn)證,那肯定是有問(wèn)題的;但如果一個(gè)方法體通過(guò)了字節(jié)碼驗(yàn)證,也不能說(shuō)明其一定就是安全的。
  4. 符號(hào)引用驗(yàn)證,發(fā)生在虛擬機(jī)將符號(hào)引用轉(zhuǎn)化為直接引用的時(shí)候,這個(gè)轉(zhuǎn)化動(dòng)作將在“解析階段”中發(fā)生。驗(yàn)證符號(hào)引用中通過(guò)字符串描述的權(quán)限定名是否能找到對(duì)應(yīng)的類;在指定類中是否存在符合方法字段的描述符及簡(jiǎn)單名稱所描述的方法和字段;符號(hào)引用中的類、字段和方法的訪問(wèn)性(`private、protected、public、default`)是否可被當(dāng)前類訪問(wèn)

驗(yàn)證階段對(duì)于虛擬機(jī)的類加載機(jī)制來(lái)說(shuō),不一定是必要的階段。如果所運(yùn)行的全部代碼確認(rèn)是安全的,可以使用`-Xverify:none`參數(shù)來(lái)關(guān)閉大部分的類驗(yàn)證措施,以縮短虛擬機(jī)類加載時(shí)間。

準(zhǔn)備

準(zhǔn)備階段是為類的靜態(tài)變量分配內(nèi)存并將其初始化為默認(rèn)值,這些內(nèi)存都將在方法區(qū)中進(jìn)行分配。準(zhǔn)備階段不分配類中的實(shí)例變量的內(nèi)存,實(shí)例變量將會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一起分配在Java堆中。

有幾點(diǎn)需要注意:

1.在方法區(qū)中分配內(nèi)存的只有類變量(被`static`修飾的變量),而不包括實(shí)例變量,實(shí)例變量將會(huì)跟隨著對(duì)象在 Java 堆中為其分配內(nèi)存

2.初始化類變量的時(shí)候,是將類變量初始化為其類型對(duì)應(yīng)的`0`值,比如有如下類變量,在準(zhǔn)備階段完成之后`val`的值是`0`而不是 `123`,為 `val`復(fù)制為`123`,是在后面要講的初始化階段之后

  1. //在準(zhǔn)備階段value初始值為0 。在初始化階段才會(huì)變?yōu)?23 。 
  2. public static int val=123; 

3. 對(duì)于常量,其對(duì)應(yīng)的值會(huì)在編譯階段就存儲(chǔ)在字段表的`ConstantValue`屬性當(dāng)中,所以在準(zhǔn)備階段結(jié)束之后,常量的值就是`ConstantValue`所指定的值了,比如如下,在準(zhǔn)備階段結(jié)束之后,`val`的值就是`123`了。

  1. public static final int val = 123; 

解析

解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程。

符號(hào)引用(Symbolic Reference):符號(hào)引用以一組符號(hào)來(lái)描述所引用的目標(biāo),符號(hào)可以是任何形式的字面量,只要使用時(shí)能無(wú)歧義地定位到目標(biāo)即可。符號(hào)引用與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局無(wú)關(guān),引用的目標(biāo)并不一定已經(jīng)加載到內(nèi)存中。

直接引用(Direct Reference):直接引用可以是直接指向目標(biāo)的指針、相對(duì)偏移量或是一個(gè)能間接定位到目標(biāo)的句柄。直接引用是與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局相關(guān)的,如果有了直接引用,那么引用的目標(biāo)必定已經(jīng)在內(nèi)存中存在。

初始化

類的初始化階段才是真正開(kāi)始執(zhí)行類中定義的 Java 程序代碼。初始化說(shuō)白了就是調(diào)用類構(gòu)造器`()`的過(guò)程,在類的構(gòu)造器中會(huì)為類變量初始化定義的值,會(huì)執(zhí)行靜態(tài)代碼塊中的內(nèi)容。下面將介紹幾點(diǎn)和開(kāi)發(fā)者關(guān)系較為緊密的注意點(diǎn)

1. 類構(gòu)造器`()`是由編譯器自動(dòng)收集類中出現(xiàn)的類變量、靜態(tài)代碼塊中的語(yǔ)句合并產(chǎn)生的,收集的順序是在源文件中出現(xiàn)的順序決定的,靜態(tài)代碼塊可以訪問(wèn)出現(xiàn)在靜態(tài)代碼塊之前的類變量,出現(xiàn)的靜態(tài)代碼塊之后的類變量,只可以賦值,但是不能訪問(wèn),比如如下代碼

 

看了這篇你還不懂JVM 中的類加載機(jī)制?

 

2. `()`類構(gòu)造器和`()`實(shí)例構(gòu)造器不同,類構(gòu)造器不需要顯示的父類的類構(gòu)造,在子類的類構(gòu)造器調(diào)用之前,會(huì)自動(dòng)的調(diào)用父類的類構(gòu)造器。因此虛擬機(jī)中第一個(gè)被調(diào)用的`()`方法是 `java.lang.Object`的類構(gòu)造器

3. 由于父類的類構(gòu)造器優(yōu)先于子類的類構(gòu)造器執(zhí)行,所以父類中的`static{}`代碼塊也優(yōu)先于子類的`static{}`執(zhí)行

4. 類構(gòu)造器`()`對(duì)于類來(lái)說(shuō)并不是必需的,如果一個(gè)類中沒(méi)有類變量,也沒(méi)有`static{}`,那這個(gè)類不會(huì)有類構(gòu)造器`()`

5. 接口中不能有`static{}`,但是接口中也可以有類變量,所以接口中也可以有類構(gòu)造器 `{}`,但是接口的類構(gòu)造器和類的類構(gòu)造器有所不同,接口在調(diào)用類構(gòu)造器的時(shí)候,如果不需要,不用調(diào)用父接口的類構(gòu)造器,除非用到了父接口中的類變量,接口的實(shí)現(xiàn)類在初始化的時(shí)候也不會(huì)調(diào)用接口的類構(gòu)造器

6. 虛擬機(jī)會(huì)保證一個(gè)類的`()`方法在多線程環(huán)境中被正確地加鎖、同步,如果多個(gè)線程同時(shí)去初始化一個(gè)類,那么只有一個(gè)線程去執(zhí)行這個(gè)類的類構(gòu)造器`()`,其他線程會(huì)被阻塞,直到活動(dòng)線程執(zhí)行完類構(gòu)造器`()`方法

 

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2021-06-16 00:57:16

JVM加載機(jī)制

2021-09-06 07:58:47

鏈表數(shù)據(jù)結(jié)構(gòu)

2023-08-09 09:03:49

CPU密集型運(yùn)算

2023-10-31 16:00:51

類加載機(jī)制Java

2021-05-06 15:59:27

Linux性能優(yōu)化

2022-02-18 06:56:18

Wi-Fi路由器局域網(wǎng)

2017-03-08 10:30:43

JVMJava加載機(jī)制

2021-04-29 11:18:14

JVM加載機(jī)制

2017-09-20 08:07:32

java加載機(jī)制

2020-02-24 21:50:24

瓶頸數(shù)據(jù)庫(kù)

2023-08-02 08:38:27

JVM加載機(jī)制

2024-12-02 09:01:23

Java虛擬機(jī)內(nèi)存

2024-03-12 07:44:53

JVM雙親委托機(jī)制類加載器

2021-12-28 12:01:59

Kafka 消費(fèi)者機(jī)制

2022-10-08 08:34:34

JVM加載機(jī)制代碼

2021-05-28 11:54:29

MySQL數(shù)據(jù)庫(kù)主從復(fù)制

2019-07-31 15:56:57

Jvm虛擬機(jī)Content

2023-05-10 11:07:18

2021-09-24 08:10:40

Java 語(yǔ)言 Java 基礎(chǔ)

2020-10-26 11:20:04

jvm類加載Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩精品成人 | 久久精品国产久精国产 | 福利在线看 | 欧美日韩一区二区在线 | 欧美日韩亚洲一区 | 欧美一级片黄色 | 国产精品成人一区二区三区 | 精品一区二区在线看 | 久久综合色综合 | 91亚洲精品久久久电影 | 国产一区不卡 | 亚洲国产精品久久久 | 男人av网| 国产日韩欧美中文 | 伊人久久精品 | 免费黄色的视频 | 四虎成人免费视频 | 久久com| 色爱综合网 | 午夜视频免费在线观看 | 国产99久久精品一区二区永久免费 | 久久久精品网 | av天空 | 欧美日韩精品一区二区三区四区 | 一级毛片在线播放 | 蜜桃视频一区二区三区 | 国产精品成人一区二区三区 | aaaa网站 | 亚洲在线看 | 一区二区国产在线 | 欧美色999| 日本色婷婷 | 成人做爰www免费看 午夜精品久久久久久久久久久久 | 涩涩鲁亚洲精品一区二区 | 久久精品二区亚洲w码 | 国产精品爱久久久久久久 | 久久成人一区 | 日韩午夜影院 | 国产污视频在线 | 亚洲网址在线观看 | 欧美日韩在线一区二区 |