首頁 > Java > Java面試題 > 主體

面試官:說一下類別載入的過程(10張圖解)

發布: 2023-08-23 15:05:47
轉載
1570 人瀏覽過

載入

#當我們要使用一個類別的時候,要透過ClassLoader將類別載入到記憶體中

「類別載入階段主要完成以下三件事情」

  1. 透過全類名,取得類的二進位流
  2. 解析類別的二進位流為方法區內的資料結構
  3. 建立一個java.lang.Class類別的實例,表示該類型,作為方法區這個類別的存取入口
面試官:說一下類別載入的過程(10張圖解)

「透過全類別名,取得類別的二進位流的方式有很多種”

  1. 從zip壓縮包取得
  2. 從網路取得
  3. 執行階段計算生成,如動態代理技術
  4. ...

#「對於非陣列類型的載入階段,也就是可以使用Java虛擬機器內建的類別載入器去完成,也可以使用使用者自訂的類別載入器去完成”

連結

「連結這個階段主要分為3個部分,驗證,準備,解析」

驗證

#「驗證階段主要是確保Class檔案的格式正確,運行時不會危害虛擬機器的安全」

驗證階段的規則很多,但大致分為如下4個階段面試官:說一下類別載入的過程(10張圖解)「具體詳細的內容,我就不詳細解釋了,可以看《深入理解Java虛擬機》,本篇文章偏向於做一個總結,把握類別加載的一個整體流程,而不對細節進行闡述”

準備

「準備階段主要是為類別的靜態變數分配內存,並將其初始化為默認值”

常見的資料類型的預設值如下

#
資料型別 預設值
byte # (byte)0
short (short)0
int #0
long 0L
float 0.0f
#double 0.0d
boolean false
char '\u0000'
#參考 null
##########################

「如果類別靜態變數的欄位屬性表中存在ConstantValue屬性,則直接執行賦值語句」

那麼什麼情況下類別靜態變數的欄位屬性表中存在ConstantValue屬性呢?

  1. 類別靜態變數為基本資料類型,並且被final修飾
  2. #類別靜態變數為String類型,被final修飾,並且以字面量的形式賦值

為了方便查看Class檔案的字節碼,我在IDEA下載了一個外掛程式jclasslib Bytecode viewer,非常方便。用以下程式碼透過字節碼的形式驗證一下

public class Person {

    private static int age = 10;
    private static final int length = 160;
    private static final String name = "name";
    private static final String loc = new String("loc");
}
登入後複製

面試官:說一下類別載入的過程(10張圖解)「所以length和name屬性在準備階段就會賦值為ConstantValue指定的值」

#「那麼age和loc屬性會在哪個階段賦值呢?是在初始化階段,後面會詳細介紹哈」面試官:說一下類別載入的過程(10張圖解)

##解析

「將類,接口,字段和方法的符號引用(在常數池中)轉為直接引用」符號引用:用一組符號來描述所引用的目標 直接引用;直接指向指向目標的指標

加入我寫了一個如下的類別

public class Student {

    private String name;
    private int age;

    public String getName() {
        return this.name;
    }
}
登入後複製

以欄位為例,name和age對應的物件並不是直接指向記憶體位址,而是用字串來進行描述(即符號引用)。解析階段就是將這些描述轉為直接指向目標的指標(即直接引用)面試官:說一下類別載入的過程(10張圖解)

初始化

「执行类静态成员变量赋值语句和静态代码块中的语句」

面試官:說一下類別載入的過程(10張圖解)

我们把上面的Student代码改成如下形式

public class Student {

    private String name;
    private int age = 10;
    private static int gender = 1;

    {
        System.out.println("构造代码块");
    }

    static {
        System.out.println("静态代码块");
    }

    public Student() {
        System.out.println("构造函数");
    }

    public String getName() {
        return this.name;
    }
}
登入後複製

可以看到字节码中包含了3个方法,getName方法我们知道,方法里面执行了哪些逻辑?面試官:說一下類別載入的過程(10張圖解)从字节码的角度分析一波

方法」

面試官:說一下類別載入的過程(10張圖解)

从字节码可以看到方法的主要逻辑为

  1. 调用父类的方法
  2. 非静态成员变量赋值
  3. 执行构造代码块
  4. 执行构造函数

面試官:說一下類別載入的過程(10張圖解)方法」面試官:說一下類別載入的過程(10張圖解)从字节码可以看到方法的主要逻辑为

  1. 執行靜態變數的賦值語句
  2. 執行靜態程式碼區塊中的語句
  3. 需要注意的一點是,「Java虛擬機會保證子類別的方法執行前,父類別的方法已經執行完畢」

「理解方法的作用還是有必要的,因為經常有些面試題問靜態程式碼區塊,建構程式碼區塊,建構子的執行順序。」
  1. #我這裡就直接總結結論,大家可以寫demo驗證一下
  2. 「沒有繼承狀況的執行順序」
  3. 靜態程式碼區塊和靜態成員變量,執行順序由編寫順序決定(只會執行一次哈)

建構程式碼區塊和非靜態成員變量,執行順序由編寫順序決定 #建構子

面試官:說一下類別載入的過程(10張圖解)「有繼承情況的執行順序」面試官:說一下類別載入的過程(10張圖解)

#########父類別的靜態(靜態程式碼區塊,靜態成員變數),子類別的靜態(靜態程式碼區塊,靜態成員變數)(只會執行一次哈)############父類別的非靜態(構造程式碼區塊,非靜態成員變數),父類別的建構子############子類別的非靜態(建構程式碼區塊,非靜態成員變數),子類別的建構子### ##################卸載################垃圾收集不只發生在堆中,方法區上也會發生。但是對方法區的型別資料回收的條件比較嚴苛######以下圖為例,想回收方法區中的Simple類別###
  1. 需要確保堆中的Sample類別及其子類別都已經被回收
  2. #載入Sample類別的MyClassLoader已經被回收
  3. Sample類別對應的Class物件已經被回收面試官:說一下類別載入的過程(10張圖解)

可以看到對方法區的類型資料回收的條件比較苛刻,但是收效甚微,所以有些垃圾收集器不會對方法區的類型資料進行回收

總結

類別載入過程面試官:說一下類別載入的過程(10張圖解)

變數的賦值過程面試官:說一下類別載入的過程(10張圖解)

#

以上是面試官:說一下類別載入的過程(10張圖解)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:Java后端技术全栈
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!