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