MyClass.class和初始化類的研究

對於MyClass.class和getClass()方法的一點疑惑,查了一些資料,也沒有找到說的很清楚的,根據一些相關的資料和自己做的一點小實驗,做了幾點猜測,有什麼不正確的地方希望大家指正。
對於一個類,MyClass.class返回的是一個java.lang.Class,也就是一個類的描述信息。但是並沒有對類進行初始化,類的static fields也沒有被調用,所以應該只是載入了類的變量和方法的信息。
運行以下的類,可以看到c1,c2和c3都是相等的,也就是類的信息在jvm中只會裝載一次,這次的裝載可能是在聲明這個類的時候或者調用MyTest.class的時候.

public class Try1 {

 
public static void main(String args[])
 
{
  Class c1 
= Temp.class;
  Class c2 
= Temp.class;
    
  System.out.println(c1);
  System.out.println(c2);
  Class c3 
= new Temp().getClass();
  System.out.println(c3);
  
  System.out.println(c1.getName());
  System.out.println(c2.getName());
  System.out.println(c3.getName());
  
  System.out.println(
"c1=c2 "+(c1==c2));
  System.out.println(
"c1=c3 "+(c1==c3));
  System.out.println(
"c2=c3 "+(c2==c3)); 
  
  
 }

}


 

類在聲明的時候並不會調用static fields和初始化static變量,以下的程序可以很容易看出.運行只會打印Hello world,不會打印Temp中其他信息.

 

public class MyTest implements Init
 
static Class t2 = Temp.class;
 
static Temp tt; //NOTICE 
 
 MyTest()
{}
 
public static void main(String[] args) {
  System.out.println(
"Hello,World!");
  
 }

}


public class Temp {

 
public Temp(){
  System.out.println(
"==constrocts temp()==");
 }

 
static int ii = 8;
 
static {
  
int i = 100/0;
  System.out.println(
"==init temp()==");
  System.out.println(ii
+"in it");
 }

 
static Temp t = new Temp();
}


 

當訪問一個static 變量,clinit方法會被調用,關於clinit和init方法,下面zz的一篇文章解釋的很清楚,也是看到這篇文章受到的啓發.

 

public class MyTest implements Init{
 
 
static Temp tt;
 
 
static {
  System.out.println(Temp.ii);
 }
 
 
//Temp t = new Temp();  //NOTICE HERE
 MyTest(){}
 
public static void main(String[] args) {
  System.out.println(
"Hello,World!");
  MyTest m 
= new MyTest();
  
//MyTest mm;
  
//System.out.println(MyTest.i);
  
//System.out.println(m.t1==m.t2);
  
 }

}

 

運行可以看到如下錯誤信息:
java.lang.ExceptionInInitializerError
 at MyTest.<clinit>(MyTest.java:12)
Caused by: java.lang.ArithmeticException: / by zero
 at Temp.<clinit>(Temp.java:12)
 ... 1 more
Exception in thread "main"

把剛剛註釋掉的Temp t = new Temp()取消註釋 ,然後把System.out.println(Temp.ii)註釋掉,運行會發現如下的錯誤.

Hello,World!
Exception in thread "main" java.lang.ExceptionInInitializerError
 at MyTest.<init>(MyTest.java:16)
 at MyTest.main(MyTest.java:20)
Caused by: java.lang.ArithmeticException: / by zero
 at Temp.<clinit>(Temp.java:12)
 ... 2 more

 

 

public class Temp {

 
public Temp(){
  System.out.println(
"==constrocts temp()==");
 }

 
static int ii = 8;
 
static {
 
// int i = 10/0;
  System.out.println("==init temp()==");
  System.out.println(ii
+"in it");
 }

 
//static Temp t = new Temp();
 Temp2 t2 = new Temp2();
}

public class Temp2 {
 
static {
  
int i = 100/0
 }

}

public class MyTest{
 
static 
  System.out.println(Temp.ii);  
 }

 MyTest()
{}
 
public static void main(String[] args) {
  System.out.println(
"Hello,World!");
  MyTest m 
= new MyTest();
  
 }

}



由此可以發現初始化一個變量調用的是init方法對類進行初始化,而訪問static變量時,調用的是clinit方法對類初始化.
初步猜測類的加載由以下三個步驟構成:

聲明或MyTest.class:   加載類的變量和方法名,獲得類的基本信息.
clinit:   對類的static fields調用,初始化static變量.不會爲非static變量賦值.
init:      對非static變量賦值,調用構造函數.

 

發佈了21 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章