類的主動使用和被動使用

  • 2022 年 2 月 23 日
  • 筆記

 

即判斷是否執行<clinit>方法

被動使用有可能會載入類(JVM規範里沒有說明),根據不同虛擬機實現,如果在載入的過程中,遇到了.class文件的缺失或者存在錯誤,類載入器只會在首次主動使用它們時才會報錯,如果一直沒有主動使用,則不會報錯

主動

一,使用new關鍵字或者通過反射、克隆、反序列化

二,調用類的靜態方法。

三,當使用類、介面的靜態欄位時(final修飾特殊考慮)。

四,當使用java.lang.reflect包中的方法反射類的方法時。

五,當初始化子類時,如果發現其父類還沒有進行過初始化,則需要先觸發父類的初始化

interface Parent {
Thread thread = new Thread(){ //匿名內部類
{
System.out.println(“Thread…Parent”);
}
};
}
class Child implements Parent {
public static int b = 5;
}
public class Test04 {
public static void main(String[] args) {
System.out.println(Child.b);
}
}
//介面繼承或者實現介面類,只有當程式首次使用特定介面的靜態欄位時,才會導致該介面的初始化,而且是引用類型的
//例子中初始化Chlid但並沒有初始化父介面。

六,如果一個介面定義了default方法,那麼直接實現或者間接實現該介面的類的初始化,該介面要在其之前被初始化。

interface Parent {
Thread thread = new Thread(){ //匿名內部類
{
System.out.println(“Thread…Parent”);
}
};
default void a(){
System.out.println(“dafsdaf”);
}
}
class Child implements Parent {
}
public class Test04 {
public static void main(String[] args) {
Child child=new Child();
}
}

七,jvm啟動時被標明為啟動類的類(如Java Test、main方法所在的類)

八,動態語言,當初次調用 MethodHandle 實例時,初始化該 MethodHandle 指向的方法所在類。

被動

一,static final的常量

class F{
static final int count = 1;
static{
System.out.println(“Initialize class F”);
}
}
public class Test6 {
public static void main(String[] args) {
int x = F.count;
}
}
//static final的常量,F的class文件刪掉,也不影響程式的正常執行,其在編譯階段就會存入調用類的常量池中

class F{
static final String s = UUID.randomUUID().toString();
static{
System.out.println(“Initialize class F”);
}
}
public class Test6 {
public static void main(String[] args) {
String x = F.s;
}
}
//運行期確定不是常量

二,當通過子類引用父類的靜態變數,不會導致子類初始化

class Dfather{
static int count = 1;
static{
System.out.println(“Initialize class Dfather”);
}
}
class Dson extends Dfather{
static{
System.out.println(“Initialize class Dson”);
}
}
public class Test4 {
public static void main(String[] args) {
int x = Dson.count;
}
}
//會載入Dson,但不會初始化,不同虛擬機不同,可通過參數 -verbose:class查看

class C{
static int a=1;
static {
System.out.println(“wdfghjkldfgh”);
}
}
public class P extends C{
static {
System.out.println(“fdsfsf”);
}
public static void main(String[] args) {
System.out.println(P.a);
}
}
//注意若運行類直接繼承則會初始化子類

三,通過數組定義類引用,不會觸發此類的初始化

class E{
static{
System.out.println(“Initialize class E”);
}
}
public class Test5 {
public static void main(String[] args) {
E[] e = new E[10];
}
}