java调用类中的静态变量时类中静态代码块什么情况会执行以及类的初始化问题?
類從被加載到虛擬機內存中開始,到卸載出內存為止,它的整個生命周期包括:加載、驗證、準備、解析、初始化、使用和卸載七個階段。
類初始化是類加載過程的最后一個階段,到初始化階段,才真正開始執行類中的Java程序代碼。虛擬機規范嚴格規定了有且只有5種情況必須立即對類進行初始化:
第一種:遇到new、getstatic、putstatic、invokestatic這四條字節碼指令時,如果類還沒有進行過初始化,則需要先觸發其初始化。生成這四條指令最常見的Java代碼場景是:使用new關鍵字實例化對象時、讀取或設置一個類的靜態字段(static)時(被static修飾又被final修飾的,已在編譯期把結果放入常量池的靜態字段除外)、以及調用一個類的靜態方法時。
第二種:使用Java.lang.refect包的方法對類進行反射調用時,如果類還沒有進行過初始化,則需要先觸發其初始化。
第三種:當初始化一個類的時候,如果發現其父類還沒有進行初始化,則需要先觸發其父類的初始化。
第四種:當虛擬機啟動時,用戶需要指定一個要執行的主類,虛擬機會先執行該主類。
第五種:當使用JDK1.5支持時,如果一個java.langl.incoke.MethodHandle實例最后的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且這個方法句柄所對應的類沒有進行過初始化,則需要先觸發其初始
執行代碼:
package com.spring.partise;import java.util.Random;class A{static final int numA = Main.rand.nextInt(100);static{System.out.println("I am A");} } class B{static final int numB = 2;static{System.out.println("I am B");} } class C{static int numC = 3;static{System.out.println("I am C");} } public class Main {static Random rand = new Random();public static void main(String[] args) throws Exception {System.out.println("---------------------------");System.out.println(A.numA);//會執行static中的方法System.out.println("---------------------------");System.out.println(B.numB);//不會執行static中的方法System.out.println("---------------------------");System.out.println(C.numC);} }執行結果:
--------------------------- I am A 22 --------------------------- 2 --------------------------- I am C 3總結:如果一個static final值是“編譯期常量”,就像static final int numB = 2;那樣,那么這個值不需要對B類進行初始化就可以讀取。但是,如果只是將一個域設置為static和final的,那不一足以確保這種行為,例如,對static final int numA = Main.rand.nextInt(100);的訪問將強制進行類的初始化,因為它不是一個編譯期常量。
如果一個static 域不是final,那么在對它訪問時,總是要求在它被讀取之前,要先進行鏈接(為這個域分配存儲空間)和初始化(初始化該存儲空間)就像static int numC = 3;那樣!!!
總結
以上是生活随笔為你收集整理的java调用类中的静态变量时类中静态代码块什么情况会执行以及类的初始化问题?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jetty优秀文章
- 下一篇: Jupyter notebook应用总结