欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

通過(guò)面試題解析 Java 類加載機(jī)制

 更新時(shí)間:2019年05月31日 08:43:40   作者:陳樹(shù)義  
類加載是 Java 語(yǔ)言的一個(gè)創(chuàng)新,也是 Java 語(yǔ)言流行的重要原因之一。它使得 Java 類可以被動(dòng)態(tài)加載到 Java 虛擬機(jī)中并執(zhí)行。下面小編和大家來(lái)一起學(xué)習(xí)一下吧

在許多Java面試中,我們經(jīng)常會(huì)看到關(guān)于Java類加載機(jī)制的考察,例如下面這道題:

class Grandpa
{
static
{
System.out.println("爺爺在靜態(tài)代碼塊");
}
} 
class Father extends Grandpa
{
static
{
System.out.println("爸爸在靜態(tài)代碼塊");
}
public static int factor = 25;
public Father()
{
System.out.println("我是爸爸~");
}
}
class Son extends Father
{
static 
{
System.out.println("兒子在靜態(tài)代碼塊");
}
public Son()
{
System.out.println("我是兒子~");
}
}
public class InitializationDemo
{
public static void main(String[] args)
{
System.out.println("爸爸的歲數(shù):" + Son.factor); //入口
}
}

請(qǐng)寫出最后的輸出字符串。

正確答案是:

爺爺在靜態(tài)代碼塊
爸爸在靜態(tài)代碼塊
爸爸的歲數(shù):25

我相信很多同學(xué)看到這個(gè)題目之后,表情是崩潰的,完全不知道從何入手。有的甚至遇到了幾次,仍然無(wú)法找到正確的解答思路。

其實(shí)這種面試題考察的就是你對(duì)Java類加載機(jī)制的理解。

如果你對(duì)Java加載機(jī)制不理解,那么你是無(wú)法解答這道題目的。

所以這篇文章,我先帶大家學(xué)習(xí)Java類加載的基礎(chǔ)知識(shí),然后再實(shí)戰(zhàn)分析幾道題目讓大家掌握思路。

下面我們先來(lái)學(xué)習(xí)下Java類加載機(jī)制的七個(gè)階段。

Java類加載機(jī)制的七個(gè)階段

當(dāng)我們的Java代碼編譯完成后,會(huì)生成對(duì)應(yīng)的 class 文件。接著我們運(yùn)行java Demo命令的時(shí)候,我們其實(shí)是啟動(dòng)了JVM 虛擬機(jī)執(zhí)行 class 字節(jié)碼文件的內(nèi)容。而 JVM 虛擬機(jī)執(zhí)行 class 字節(jié)碼的過(guò)程可以分為七個(gè)階段:加載、驗(yàn)證、準(zhǔn)備、解析、初始化、使用、卸載。

加載

下面是對(duì)于加載過(guò)程最為官方的描述。

加載階段是類加載過(guò)程的第一個(gè)階段。在這個(gè)階段,JVM 的主要目的是將字節(jié)碼從各個(gè)位置(網(wǎng)絡(luò)、磁盤等)轉(zhuǎn)化為二進(jìn)制字節(jié)流加載到內(nèi)存中,接著會(huì)為這個(gè)類在 JVM 的方法區(qū)創(chuàng)建一個(gè)對(duì)應(yīng)的 Class 對(duì)象,這個(gè) Class 對(duì)象就是這個(gè)類各種數(shù)據(jù)的訪問(wèn)入口。

其實(shí)加載階段用一句話來(lái)說(shuō)就是:把代碼數(shù)據(jù)加載到內(nèi)存中。這個(gè)過(guò)程對(duì)于我們解答這道問(wèn)題沒(méi)有直接的關(guān)系,但這是類加載機(jī)制的一個(gè)過(guò)程,所以必須要提一下。

驗(yàn)證

當(dāng) JVM 加載完 Class 字節(jié)碼文件并在方法區(qū)創(chuàng)建對(duì)應(yīng)的 Class 對(duì)象之后,JVM 便會(huì)啟動(dòng)對(duì)該字節(jié)碼流的校驗(yàn),只有符合 JVM 字節(jié)碼規(guī)范的文件才能被 JVM 正確執(zhí)行。這個(gè)校驗(yàn)過(guò)程大致可以分為下面幾個(gè)類型:

  • JVM規(guī)范校驗(yàn)。JVM 會(huì)對(duì)字節(jié)流進(jìn)行文件格式校驗(yàn),判斷其是否符合 JVM 規(guī)范,是否能被當(dāng)前版本的虛擬機(jī)處理。例如:文件是否是以 0x cafe bene開(kāi)頭,主次版本號(hào)是否在當(dāng)前虛擬機(jī)處理范圍之內(nèi)等。
  • 代碼邏輯校驗(yàn)。JVM 會(huì)對(duì)代碼組成的數(shù)據(jù)流和控制流進(jìn)行校驗(yàn),確保 JVM 運(yùn)行該字節(jié)碼文件后不會(huì)出現(xiàn)致命錯(cuò)誤。例如一個(gè)方法要求傳入 int 類型的參數(shù),但是使用它的時(shí)候卻傳入了一個(gè) String 類型的參數(shù)。一個(gè)方法要求返回 String 類型的結(jié)果,但是最后卻沒(méi)有返回結(jié)果。代碼中引用了一個(gè)名為 Apple 的類,但是你實(shí)際上卻沒(méi)有定義 Apple 類。

當(dāng)代碼數(shù)據(jù)被加載到內(nèi)存中后,虛擬機(jī)就會(huì)對(duì)代碼數(shù)據(jù)進(jìn)行校驗(yàn),看看這份代碼是不是真的按照J(rèn)VM規(guī)范去寫的。這個(gè)過(guò)程對(duì)于我們解答問(wèn)題也沒(méi)有直接的關(guān)系,但是了解類加載機(jī)制必須要知道有這個(gè)過(guò)程。

準(zhǔn)備(重點(diǎn))

當(dāng)完成字節(jié)碼文件的校驗(yàn)之后,JVM 便會(huì)開(kāi)始為類變量分配內(nèi)存并初始化。這里需要注意兩個(gè)關(guān)鍵點(diǎn),即內(nèi)存分配的對(duì)象以及初始化的類型。

內(nèi)存分配的對(duì)象。Java 中的變量有「類變量」和「類成員變量」兩種類型,「類變量」指的是被 static 修飾的變量,而其他所有類型的變量都屬于「類成員變量」。在準(zhǔn)備階段,JVM 只會(huì)為「類變量」分配內(nèi)存,而不會(huì)為「類成員變量」分配內(nèi)存?!割惓蓡T變量」的內(nèi)存分配需要等到初始化階段才開(kāi)始。

例如下面的代碼在準(zhǔn)備階段,只會(huì)為 factor 屬性分配內(nèi)存,而不會(huì)為 website 屬性分配內(nèi)存。

public static int factor = 3;
public String website = www.cnblogs.com/chanshuyi;

初始化的類型。在準(zhǔn)備階段,JVM 會(huì)為類變量分配內(nèi)存,并為其初始化。但是這里的初始化指的是為變量賦予 Java 語(yǔ)言中該數(shù)據(jù)類型的零值,而不是用戶代碼里初始化的值。

例如下面的代碼在準(zhǔn)備階段之后,sector 的值將是 0,而不是 3。

public static int sector = 3;

但如果一個(gè)變量是常量(被 static final 修飾)的話,那么在準(zhǔn)備階段,屬性便會(huì)被賦予用戶希望的值。例如下面的代碼在準(zhǔn)備階段之后,number 的值將是 3,而不是 0。

public static final int number = 3;

之所以 static final 會(huì)直接被復(fù)制,而 static 變量會(huì)被賦予零值。其實(shí)我們稍微思考一下就能想明白了。

兩個(gè)語(yǔ)句的區(qū)別是一個(gè)有 final 關(guān)鍵字修飾,另外一個(gè)沒(méi)有。而 final 關(guān)鍵字在 Java 中代表不可改變的意思,意思就是說(shuō) number 的值一旦賦值就不會(huì)在改變了。既然一旦賦值就不會(huì)再改變,那么就必須一開(kāi)始就給其賦予用戶想要的值,因此被 final 修飾的類變量在準(zhǔn)備階段就會(huì)被賦予想要的值。而沒(méi)有被 final 修飾的類變量,其可能在初始化階段或者運(yùn)行階段發(fā)生變化,所以就沒(méi)有必要在準(zhǔn)備階段對(duì)它賦予用戶想要的值。

解析

當(dāng)通過(guò)準(zhǔn)備階段之后,JVM 針對(duì)類或接口、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用點(diǎn)限定符 7 類引用進(jìn)行解析。這個(gè)階段的主要任務(wù)是將其在常量池中的符號(hào)引用替換成直接其在內(nèi)存中的直接引用。

其實(shí)這個(gè)階段對(duì)于我們來(lái)說(shuō)也是幾乎透明的,了解一下就好。

初始化(重點(diǎn))

到了初始化階段,用戶定義的 Java 程序代碼才真正開(kāi)始執(zhí)行。在這個(gè)階段,JVM 會(huì)根據(jù)語(yǔ)句執(zhí)行順序?qū)︻悓?duì)象進(jìn)行初始化,一般來(lái)說(shuō)當(dāng) JVM 遇到下面 5 種情況的時(shí)候會(huì)觸發(fā)初始化:

  • 遇到 new、getstatic、putstatic、invokestatic 這四條字節(jié)碼指令時(shí),如果類沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化。生成這4條指令的最常見(jiàn)的Java代碼場(chǎng)景是:使用new關(guān)鍵字實(shí)例化對(duì)象的時(shí)候、讀取或設(shè)置一個(gè)類的靜態(tài)字段(被final修飾、已在編譯器把結(jié)果放入常量池的靜態(tài)字段除外)的時(shí)候,以及調(diào)用一個(gè)類的靜態(tài)方法的時(shí)候。
  • 使用 java.lang.reflect 包的方法對(duì)類進(jìn)行反射調(diào)用的時(shí)候,如果類沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其初始化。
  • 當(dāng)初始化一個(gè)類的時(shí)候,如果發(fā)現(xiàn)其父類還沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其父類的初始化。
  • 當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)要執(zhí)行的主類(包含main()方法的那個(gè)類),虛擬機(jī)會(huì)先初始化這個(gè)主類。
  • 當(dāng)使用 JDK1.7 動(dòng)態(tài)語(yǔ)言支持時(shí),如果一個(gè) java.lang.invoke.MethodHandle實(shí)例最后的解析結(jié)果 REF_getstatic,REF_putstatic,REF_invokeStatic 的方法句柄,并且這個(gè)方法句柄所對(duì)應(yīng)的類沒(méi)有進(jìn)行初始化,則需要先出觸發(fā)其初始化。

看到上面幾個(gè)條件你可能會(huì)暈了,但是不要緊,不需要背,知道一下就好,后面用到的時(shí)候回到找一下就可以了。

使用

當(dāng) JVM 完成初始化階段之后,JVM 便開(kāi)始從入口方法開(kāi)始執(zhí)行用戶的程序代碼。這個(gè)階段也只是了解一下就可以。

卸載

當(dāng)用戶程序代碼執(zhí)行完畢后,JVM 便開(kāi)始銷毀創(chuàng)建的 Class 對(duì)象,最后負(fù)責(zé)運(yùn)行的 JVM 也退出內(nèi)存。這個(gè)階段也只是了解一下就可以。

看完了Java的類加載機(jī)智之后,是不是有點(diǎn)懵呢。不怕,我們先通過(guò)一個(gè)小例子來(lái)醒醒神。

public class Book {
public static void main(String[] args)
{
System.out.println("Hello ShuYi.");
}
Book()
{
System.out.println("書的構(gòu)造方法");
System.out.println("price=" + price +",amount=" + amount);
}
{
System.out.println("書的普通代碼塊");
}
int price = 110;
static
{
System.out.println("書的靜態(tài)代碼塊");
}
static int amount = 112;
}

思考一下上面這段代碼輸出什么?

給你5分鐘思考,5分鐘后交卷,哈哈。

怎么樣,想好了嗎,公布答案了。

書的靜態(tài)代碼塊
Hello ShuYi.

怎么樣,你答對(duì)了嗎?是不是和你想得有點(diǎn)不一樣呢。

下面我們來(lái)簡(jiǎn)單分析一下,首先根據(jù)上面說(shuō)到的觸發(fā)初始化的5種情況的第4種(當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)要執(zhí)行的主類(包含main()方法的那個(gè)類),虛擬機(jī)會(huì)先初始化這個(gè)主類),我們會(huì)進(jìn)行類的初始化。

那么類的初始化順序到底是怎么樣的呢?

重點(diǎn)來(lái)了!

重點(diǎn)來(lái)了!

重點(diǎn)來(lái)了!

在我們代碼中,我們只知道有一個(gè)構(gòu)造方法,但實(shí)際上Java代碼編譯成字節(jié)碼之后,是沒(méi)有構(gòu)造方法的概念的,只有類初始化方法 和 對(duì)象初始化方法 。

那么這兩個(gè)方法是怎么來(lái)的呢?

類初始化方法。編譯器會(huì)按照其出現(xiàn)順序,收集類變量的賦值語(yǔ)句、靜態(tài)代碼塊,最終組成類初始化方法。類初始化方法一般在類初始化的時(shí)候執(zhí)行。

上面的這個(gè)例子,其類初始化方法就是下面這段代碼了:

static
{
System.out.println("書的靜態(tài)代碼塊");
}
static int amount = 112;

對(duì)象初始化方法。編譯器會(huì)按照其出現(xiàn)順序,收集成員變量的賦值語(yǔ)句、普通代碼塊,最后收集構(gòu)造函數(shù)的代碼,最終組成對(duì)象初始化方法。對(duì)象初始化方法一般在實(shí)例化類對(duì)象的時(shí)候執(zhí)行。
上面這個(gè)例子,其對(duì)象初始化方法就是下面這段代碼了:

{
System.out.println("書的普通代碼塊");
}
int price = 110;
System.out.println("書的構(gòu)造方法");
System.out.println("price=" + price +",amount=" + amount);

類初始化方法 和 對(duì)象初始化方法 之后,我們?cè)賮?lái)看這個(gè)例子,我們就不難得出上面的答案了。

但細(xì)心的朋友一定會(huì)發(fā)現(xiàn),其實(shí)上面的這個(gè)例子其實(shí)沒(méi)有執(zhí)行對(duì)象初始化方法。

因?yàn)槲覀兇_實(shí)沒(méi)有進(jìn)行 Book 類對(duì)象的實(shí)例化。如果你在 main 方法中增加 new Book() 語(yǔ)句,你會(huì)發(fā)現(xiàn)對(duì)象的初始化方法執(zhí)行了!

感興趣的朋友可以自己動(dòng)手試一下,我這里就不執(zhí)行了。

通過(guò)了上面的理論和簡(jiǎn)單例子,我們下面進(jìn)入更加復(fù)雜的實(shí)戰(zhàn)分析吧!

實(shí)戰(zhàn)分析

class Grandpa
{
static
{
System.out.println("爺爺在靜態(tài)代碼塊");
}
} 
class Father extends Grandpa
{
static
{
System.out.println("爸爸在靜態(tài)代碼塊");
}

public static int factor = 25;

public Father()
{
System.out.println("我是爸爸~");
}
}
class Son extends Father
{
static 
{
System.out.println("兒子在靜態(tài)代碼塊");
}

public Son()
{
System.out.println("我是兒子~");
}
}
public class InitializationDemo
{
public static void main(String[] args)
{
System.out.println("爸爸的歲數(shù):" + Son.factor); //入口
}
}


思考一下,上面的代碼最后的輸出結(jié)果是什么?

最終的輸出結(jié)果是:

爺爺在靜態(tài)代碼塊
爸爸在靜態(tài)代碼塊
爸爸的歲數(shù):25

也許會(huì)有人問(wèn)為什么沒(méi)有輸出「兒子在靜態(tài)代碼塊」這個(gè)字符串?

這是因?yàn)閷?duì)于靜態(tài)字段,只有直接定義這個(gè)字段的類才會(huì)被初始化(執(zhí)行靜態(tài)代碼塊)。因此通過(guò)其子類來(lái)引用父類中定義的靜態(tài)字段,只會(huì)觸發(fā)父類的初始化而不會(huì)觸發(fā)子類的初始化。

對(duì)面上面的這個(gè)例子,我們可以從入口開(kāi)始分析一路分析下去:

  • 首先程序到 main 方法這里,使用標(biāo)準(zhǔn)化輸出 Son 類中的 factor 類成員變量,但是 Son 類中并沒(méi)有定義這個(gè)類成員變量。于是往父類去找,我們?cè)?Father 類中找到了對(duì)應(yīng)的類成員變量,于是觸發(fā)了 Father 的初始化。
  • 但根據(jù)我們上面說(shuō)到的初始化的 5 種情況中的第 3 種(當(dāng)初始化一個(gè)類的時(shí)候,如果發(fā)現(xiàn)其父類還沒(méi)有進(jìn)行過(guò)初始化,則需要先觸發(fā)其父類的初始化)。我們需要先初始化 Father 類的父類,也就是先初始化 Grandpa 類再初始化 Father 類。于是我們先初始化 Grandpa 類輸出:「爺爺在靜態(tài)代碼塊」,再初始化 Father 類輸出:「爸爸在靜態(tài)代碼塊」。
  • 最后,所有父類都初始化完成之后,Son 類才能調(diào)用父類的靜態(tài)變量,從而輸出:「爸爸的歲數(shù):25」。

怎么樣,是不是覺(jué)得豁然開(kāi)朗呢。

我們?cè)賮?lái)看一下一個(gè)更復(fù)雜點(diǎn)的例子,看看輸出結(jié)果是啥。

class Grandpa
{
static
{
System.out.println("爺爺在靜態(tài)代碼塊");
}
public Grandpa() {
System.out.println("我是爺爺~");
}
}
class Father extends Grandpa
{
static
{
System.out.println("爸爸在靜態(tài)代碼塊");
}
public Father()
{
System.out.println("我是爸爸~");
}
}
class Son extends Father
{
static 
{
System.out.println("兒子在靜態(tài)代碼塊");
}
public Son()
{
System.out.println("我是兒子~");
}
}
public class InitializationDemo
{
public static void main(String[] args)
{
new Son(); //入口
}
}

輸出結(jié)果是:

爺爺在靜態(tài)代碼塊
爸爸在靜態(tài)代碼塊
兒子在靜態(tài)代碼塊
我是爺爺~
我是爸爸~
我是兒子~

怎么樣,是不是覺(jué)得這道題和上面的有所不同呢。

讓我們仔細(xì)來(lái)分析一下上面代碼的執(zhí)行流程:

  • 首先在入口這里我們實(shí)例化一個(gè) Son 對(duì)象,因此會(huì)觸發(fā) Son 類的初始化,而 Son 類的初始化又會(huì)帶動(dòng) Father 、Grandpa 類的初始化,從而執(zhí)行對(duì)應(yīng)類中的靜態(tài)代碼塊。因此會(huì)輸出:「爺爺在靜態(tài)代碼塊」、「爸爸在靜態(tài)代碼塊」、「兒子在靜態(tài)代碼塊」。
  • 當(dāng) Son 類完成初始化之后,便會(huì)調(diào)用 Son 類的構(gòu)造方法,而 Son 類構(gòu)造方法的調(diào)用同樣會(huì)帶動(dòng) Father、Grandpa 類構(gòu)造方法的調(diào)用,最后會(huì)輸出:「我是爺爺~」、「我是爸爸~」、「我是兒子~」。

看完了兩個(gè)例子之后,相信大家都胸有成足了吧。

下面給大家看一個(gè)特殊點(diǎn)的例子,有點(diǎn)難哦!

public class Book {
public static void main(String[] args)
{
staticFunction();
}
static Book book = new Book();
static
{
System.out.println("書的靜態(tài)代碼塊");
}
{
System.out.println("書的普通代碼塊");
}
Book()
{
System.out.println("書的構(gòu)造方法");
System.out.println("price=" + price +",amount=" + amount);
}
public static void staticFunction(){
System.out.println("書的靜態(tài)方法");
}
int price = 110;
static int amount = 112;
}

上面這個(gè)例子的輸出結(jié)果是:

書的普通代碼塊
書的構(gòu)造方法
price=110,amount=0
書的靜態(tài)代碼塊
書的靜態(tài)方法

下面我們一步步來(lái)分析一下代碼的整個(gè)執(zhí)行流程。

在上面兩個(gè)例子中,因?yàn)?main 方法所在類并沒(méi)有多余的代碼,我們都直接忽略了 main 方法所在類的初始化。

但在這個(gè)例子中,main 方法所在類有許多代碼,我們就并不能直接忽略了。

  • 當(dāng) JVM 在準(zhǔn)備階段的時(shí)候,便會(huì)為類變量分配內(nèi)存和進(jìn)行初始化。此時(shí),我們的 book 實(shí)例變量被初始化為 null,amount 變量被初始化為 0。
  • 當(dāng)進(jìn)入初始化階段后,因?yàn)?Book 方法是程序的入口,根據(jù)我們上面說(shuō)到的類初始化的五種情況的第四種(當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要指定一個(gè)要執(zhí)行的主類(包含main()方法的那個(gè)類),虛擬機(jī)會(huì)先初始化這個(gè)主類)。所以JVM 會(huì)初始化 Book 類,即執(zhí)行類構(gòu)造器 。
  • JVM 對(duì) Book 類進(jìn)行初始化首先是執(zhí)行類構(gòu)造器(按順序收集類中所有靜態(tài)代碼塊和類變量賦值語(yǔ)句就組成了類構(gòu)造器 ),后執(zhí)行對(duì)象的構(gòu)造器(按順序收集成員變量賦值和普通代碼塊,最后收集對(duì)象構(gòu)造器,最終組成對(duì)象構(gòu)造器 )。

對(duì)于 Book 類,其類構(gòu)造方法()可以簡(jiǎn)單表示如下:

static Book book = new Book();
static
{
System.out.println("書的靜態(tài)代碼塊");
}
static int amount = 112;

于是首先執(zhí)行static Book book = new Book();這一條語(yǔ)句,這條語(yǔ)句又觸發(fā)了類的實(shí)例化。于是 JVM 執(zhí)行對(duì)象構(gòu)造器 ,收集后的對(duì)象構(gòu)造器 代碼:

{
System.out.println("書的普通代碼塊");
}
int price = 110;
Book()
{
System.out.println("書的構(gòu)造方法");
System.out.println("price=" + price +", amount=" + amount);
}

于是此時(shí) price 賦予 110 的值,輸出:「書的普通代碼塊」、「書的構(gòu)造方法」。而此時(shí) price 為 110 的值,而 amount 的賦值語(yǔ)句并未執(zhí)行,所以只有在準(zhǔn)備階段賦予的零值,所以之后輸出「price=110,amount=0」。

當(dāng)類實(shí)例化完成之后,JVM 繼續(xù)進(jìn)行類構(gòu)造器的初始化:

static Book book = new Book(); //完成類實(shí)例化
static
{
System.out.println("書的靜態(tài)代碼塊");
}
static int amount = 112;

即輸出:「書的靜態(tài)代碼塊」,之后對(duì) amount 賦予 112 的值。

到這里,類的初始化已經(jīng)完成,JVM 執(zhí)行 main 方法的內(nèi)容。

public static void main(String[] args)
{
staticFunction();
}

即輸出:「書的靜態(tài)方法」。

方法論

從上面幾個(gè)例子可以看出,分析一個(gè)類的執(zhí)行順序大概可以按照如下步驟:

  • 確定類變量的初始值。在類加載的準(zhǔn)備階段,JVM 會(huì)為類變量初始化零值,這時(shí)候類變量會(huì)有一個(gè)初始的零值。如果是被 final 修飾的類變量,則直接會(huì)被初始成用戶想要的值。
  • 初始化入口方法。當(dāng)進(jìn)入類加載的初始化階段后,JVM 會(huì)尋找整個(gè) main 方法入口,從而初始化 main 方法所在的整個(gè)類。當(dāng)需要對(duì)一個(gè)類進(jìn)行初始化時(shí),會(huì)首先初始化類構(gòu)造器(),之后初始化對(duì)象構(gòu)造器()。
  • 初始化類構(gòu)造器。JVM 會(huì)按順序收集類變量的賦值語(yǔ)句、靜態(tài)代碼塊,最終組成類構(gòu)造器由 JVM 執(zhí)行。
  • 初始化對(duì)象構(gòu)造器。JVM 會(huì)按照收集成員變量的賦值語(yǔ)句、普通代碼塊,最后收集構(gòu)造方法,將它們組成對(duì)象構(gòu)造器,最終由 JVM 執(zhí)行。

如果在初始化 main 方法所在類的時(shí)候遇到了其他類的初始化,那么就先加載對(duì)應(yīng)的類,加載完成之后返回。如此反復(fù)循環(huán),最終返回 main 方法所在類。

結(jié)語(yǔ)

看完了上面的解析之后,再去看看開(kāi)頭那道題是不是覺(jué)得簡(jiǎn)單多了呢。很多東西就是這樣,掌握了一定的方法和知識(shí)之后,原本困難的東西也變得簡(jiǎn)單許多了。

一時(shí)沒(méi)有看懂也不要灰心,畢竟我也是用了不少的時(shí)間才弄懂的。不懂的話可以多看幾遍。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot整合Groovy腳本實(shí)現(xiàn)動(dòng)態(tài)編程詳解

    SpringBoot整合Groovy腳本實(shí)現(xiàn)動(dòng)態(tài)編程詳解

    這篇文章主要為大家介紹了SpringBoot整合Groovy腳本實(shí)現(xiàn)動(dòng)態(tài)編程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Java中的注解、元注解詳細(xì)解析

    Java中的注解、元注解詳細(xì)解析

    這篇文章主要介紹了Java中的注解、元注解詳細(xì)解析,注解也叫元數(shù)據(jù),與類、接口、枚舉是在同一個(gè)層次,它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來(lái)對(duì)這些元素進(jìn)行說(shuō)明,注釋,需要的朋友可以參考下
    2023-11-11
  • Spring?MVC中的Controller進(jìn)行單元測(cè)試的實(shí)現(xiàn)

    Spring?MVC中的Controller進(jìn)行單元測(cè)試的實(shí)現(xiàn)

    本文主要介紹了如何對(duì)Spring?MVC中的Controller進(jìn)行單元測(cè)試的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Springboot 實(shí)現(xiàn)數(shù)據(jù)庫(kù)備份還原的方法

    Springboot 實(shí)現(xiàn)數(shù)據(jù)庫(kù)備份還原的方法

    這篇文章主要介紹了Springboot 實(shí)現(xiàn)數(shù)據(jù)庫(kù)備份還原的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 關(guān)于@Autowired的使用及注意事項(xiàng)

    關(guān)于@Autowired的使用及注意事項(xiàng)

    這篇文章主要介紹了關(guān)于@Autowired的使用及注意事項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java實(shí)現(xiàn)讀取TXT和CSV文件內(nèi)容

    Java實(shí)現(xiàn)讀取TXT和CSV文件內(nèi)容

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)讀取TXT和CSV文件內(nèi)容的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-02-02
  • Eclipse操作SVN時(shí)中斷鎖定,文件的解鎖方法

    Eclipse操作SVN時(shí)中斷鎖定,文件的解鎖方法

    這篇文章主要介紹了Eclipse操作SVN時(shí)中斷鎖定,文件的解鎖方法,需要的朋友可以參考下
    2014-08-08
  • java.lang.annotation包詳細(xì)介紹

    java.lang.annotation包詳細(xì)介紹

    java.lang.annotation?包是 Java 標(biāo)準(zhǔn)庫(kù)中的一個(gè)核心包,專門用于定義和支持 Java 注解(Annotation),這篇文章主要介紹了java.lang.annotation包介紹,需要的朋友可以參考下
    2024-07-07
  • 利用IDEA社區(qū)版創(chuàng)建SpringBoot項(xiàng)目的詳細(xì)圖文教程

    利用IDEA社區(qū)版創(chuàng)建SpringBoot項(xiàng)目的詳細(xì)圖文教程

    大家應(yīng)該都知道Idea社區(qū)版本,默認(rèn)是不能創(chuàng)建SpringBoot項(xiàng)目的,下面這篇文章主要給大家介紹了關(guān)于利用IDEA社區(qū)版創(chuàng)建SpringBoot項(xiàng)目的詳細(xì)圖文教程,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • Java實(shí)現(xiàn)PDF打印的解決方案

    Java實(shí)現(xiàn)PDF打印的解決方案

    今天小編就為大家分享一篇關(guān)于Java實(shí)現(xiàn)PDF打印的解決方案,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12

最新評(píng)論