java - Static 标识的字段或者是代码块,真的是在类加载的时候初始化的吗?
PHPz
PHPz 2017-04-18 10:52:20
0
8
706
class AAA {
    static {
        System.out.println("class AAA static block println"); // 并没有打印此句
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("hello world!");
    }
}

一直以来都以为 static 标识的代码块或者是字段,都是在类加载的时候就被执行或者赋值了,但是这么一看....感觉自己的世界观都要被刷新了。

所以此处是类没有被加载吗?还是说我们一直以来认为的,静态代码块、字段都在类加载的时候被初始化的,这个观点是错误的?

在《深入理解Java虚拟机:JVM高级特性与最佳实践 第2版》中找到一些线索,如下图:

所以,照这么说,是在第一次主动访问该类的时候执行?小弟好生迷惑啊....大家快说说你们的观点

PHPz
PHPz

学习是最好的投资!

全部回覆(8)
左手右手慢动作

類別初始化和物件初始化。

static包含的程式碼區塊和變數只有在類別初始化的時候才會執行,而初始化的五種條件你也知道啦。

補充說明清楚吧。
首先,你即使放在同一個.java檔案中,編譯後,這還是兩個不同的class文件,不信你看看bin對應的套件下面產生的.class文件。
第二,類別初始化的時候,就會初始化類別的靜態變數和運行靜態程式碼區塊。所以,虛擬機器規定了五種初始化的條件,例如使用了new,getstatic,putstatic指令,main函數所在的類,反射,父類等情況。而,除開這五種情況,是不能觸發類別的初始化的。如你程式碼中所示Main.class中,並沒有任何關於AAA.class的呼叫或父子關係或反射。所以,AAA.class自然不會初始化。

可以看看的另一篇部落格java類別的載入過程

明白了嗎?

阿神

-XX:+TraceClassLoading
加上這個會發現沒載AAA

洪涛

這裡有兩個概念要擼一下:

  1. 類載入機制

  2. Java、編譯器、字節碼、JVM的規格與實作。

類別的載入是透過類別載入器(Classloader)完成的,載入的具體策略依賴JVM的具體實現,總的來說可以分兩種:

  1. 飢餓式加載,只要被其他類引用到了就加載。

  2. 懶惰式加載,當類別被訪問的時候才加載。

Java、編譯器、字節碼、JVM有各自的規範,彼此透過規範協同工作:

編譯按把Java程式碼編譯成規範的字節碼文件,每一個類別(外部類別、內部類別、匿名類別)都會被編譯成一個單獨的字節碼檔案(class檔案),JVM載入類別的時候就是從這些class檔案中一個個的載入。

現在回到你的程式碼:

在Java層,你把AAA、Main兩個類別放在一個檔案中,編譯器編譯後產生兩個class檔:AAA.class、Main.class。
兩個類別在程式碼組織形式上是一起的,但是編譯後卻是獨立的,並且Main並沒有引用AAA,所以無論是哪種類別加載方式都不會觸發對類別AAA的加載,也就不會執行AAA中的靜態程式碼區塊。

左手右手慢动作

真心感謝樓上熱心網友們的解答!

驗證

AAA 類別確實沒有被載入,只有 Main 類別被載入(題幹截圖:初始化條件第四條,主類別被 jvm 自動載入)

java -XX:+TraceClassLoading Main

結論

類別中 靜態欄位|程式碼區塊 真的是在類別載入的時候被初始化或是執行的!

延伸

怎麼知道類別有沒有被 jvm 所載入?

這也是我一直糾結的問題,一開始以為只要執行了 javac 命令,类就被 jvm 加载了,其实不然,该命令只是将 .java 文件转化成 jvm 能读懂的 .class 文件而已。

那到底怎麼知道類別有沒有被 jvm 所載入?
據 《深入理解Java虛擬機:JVM高級特性與最佳實踐 第2版》 和廣大網友的熱心解答可知,並沒有明確的時機規定了啥時候會被加載!

但是! jvm 明確規定了類別被初始化的時機-就是題幹上截圖部分那四種!而類別的載入是優先於類別初始化的,所以這裡,我們暫且可以認為這幾種情況就是觸發類別載入的條件。

小弟愚昧,總結不妥之處,麻煩大家指正!感謝

PHPzhong

把你的Main.java和AAA.java放在同一個資料夾裡,

在main函數裡寫

Class.forName("AAA");

執行

大家讲道理

執行main方法時,只會載入Main類,Main類中並沒有使用到AAA類,並不會去載入AAA類,並不是說把AAA和Main兩個類寫到同一個文件就會同時載入

大家讲道理

AAA這個類別既沒有在其他地方new,也沒有對應的去獲取或設定靜態的字段,也沒有去invoke靜態方法。
所以不會自動初始化的。

迷茫

放在兩個類別裡面了,宣告為public的類別中的mian開始執行,那個類別沒被用到自然不會被載入更別提初始化

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板