關於Jvm類加載機制,這一篇就夠了

前言

一個月沒更新了,這個月發生了太多的事情,致使更新的頻率大大下降,無論怎樣收拾心情,技術的研究不能落下!java

jvm做爲每一個java程序猿必須瞭解的知識,博主推薦一本書《深刻理解Java虛擬機》,之前博主在學校的時候看過幾遍,每一次看都有新的理解。加上工做了也有一年多的時間了,有必要好好總結一番~jvm

什麼是jvm

日常咱們編寫代碼都是編寫的.java文件,怎麼部署到機器上運行呢?經過打jar包或者war包,而後部署運行。翻譯

image

若是看過jar包的內容那麼就能知道,咱們寫的.java文件所有被編譯成了.class文件。3d

這裏發生了很重要的一個步驟——編譯:將咱們寫的程序翻譯成能被jvm讀懂的文件格式。code

值得注意的是,每個都會被編譯成一個.class文件,包括內部類等。也就是說每個.class文件都只對應咱們代碼中的一個類。對象

類的生命週期

類被加載到jvm虛擬機內存開始,到卸載出內存爲止,他的生命週期能夠分爲:加載->驗證->準備->解析->初始化->使用->卸載。blog

下面咱們來對此一一說明:接口

加載

當生成一個jar包之後,咱們編寫的程序就所有編編譯成了jvm能讀懂的.class格式。此時就須要加載了,將咱們的編譯好的.class文件加載到jvm中。此時就會有一個「類加載器」的概念。以下圖。生命週期

image

接下來一個問題,類加載器什麼時候會將一個.class加載帶jvm?也就是說什麼狀況下會加載一個類?內存

一個jar包運行的時候會指定一個main()方法做爲入口方法。首先就會將main()方法所在的類加載到jvm,當代碼執行遇到new的時候又繼續將該對象加載到jvm。

因此總結來講,就是在你的代碼中須要用到這個類的時候,就會將其加載到jvm中。

驗證

這個不須要理解的太深,很直白的道理,不能什麼阿貓阿狗都能被加載到jvm中,要不就亂套了。因此該階段就是來校驗加載進來的.class文件是否符合指定的規則。

有一個頗有趣的就是,每一個.class文件都很浪漫,由於每個.class文件都是以8個十六進制的 0×CAFEBABE,翻譯過來就是咖啡寶貝。浪漫吧?在驗證階段的第一步就是檢查.class文件是否以咖啡寶貝來開頭的。

因此咱們的流程圖能夠更新爲

image

準備

當咱們合法的把一個.class文件加載到jvm中後,此時就會進行一些準備工做。

首先爲這個類分配內存空間,而後爲類變量(被static修飾的變量)賦值一個默認的初始值。可是若是類變量同時被final修飾的話,就不是賦值初始值而是具體的值

用下面兩種狀況來講明:

public class Student{
    private static int age = 18;
}
//此時就會爲age變量分配內存空間而且爲其賦值 0 這個初始值。
public class Student{
    private static final int age = 18;
}
//age被final修飾,此時就會爲age變量分配內存空間而且爲其賦值爲 18 。

因此咱們的流程圖能夠更新爲

image

解析

解析階段就是jvm將常量池的符號引用替換爲直接引用。

簡單的來講就是咱們編寫的代碼中,當一個變量引用某個對象的時候,這個引用在.class文件中是以符號引用來存儲的。在解析階段就須要將其解析爲直接引用。若是有了直接引用,那引用的目標一定已經在內存中存在。

因此咱們的流程圖能夠更新爲

image

初始化

在準備階段咱們已經爲加載到jvm的類分配了內存空間而且爲類變量賦予了初始值。

而到了初始化階段,才真正開始執行類中定義的java程序代碼。主要有如下步驟:

  1. 爲類的靜態變量賦予正確的初始值。
  2. 執行類的靜態代碼塊。

按照順序自上而下運行類中的變量賦值語句和靜態語句,而且只有類或接口被Java程序首次主動使用時才初始化他們。若是有父類,則首先按照順序運行父類中的變量賦值語句和靜態語句。

因此咱們的流程圖能夠更新爲

image

總結

在一個靜態方法中咱們是不能直接使用非靜態變量的。當咱們使用靜態方法的時候,僅僅是初始化了靜態方法所在的類,此時只有靜態變量是被賦了值而非靜態變量是沒有被賦值的。因此在靜態方法中是不能直接使用非靜態變量的。這是個人理解,若是理解有誤,歡迎私信博主或留言哦~

相關文章
相關標籤/搜索