对于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变量赋值,调用构造函数.