/*
* test4.java
*
* created on 2007-9-21, 9:33:31
*
* to change this template, choose tools | templates
* and open the template in the editor.
*/
package test1;
/**
*
* @author hadeslee
*/
public class test4 {
private void testclassforname(string name) throws classnotfoundexception{
class c=class.forname(name);
}
private void testnewinstance(string name) throws classnotfoundexception, instantiationexception, illegalaccessexception{
class c=class.forname(name);
object obj=c.newinstance();
system.out.println(obj);
}
public static void main(string[] args)throws exception {
test4 t=new test4();
t.testclassforname("test1.b");
new b();
new b();
}
}
class a{
private int aj;
{
aj=20;
system.out.println("a成员初始化块");
}
private static int ai;
static {
ai=10;
system.out.println("a静态初始化块");
}
public a(){
system.out.println("a构造函数");
}
}
class b extends a{
private static int bi;
static {
bi=30;
system.out.println("b静态初始化块");
}
private int bj;
{
bj=40;
system.out.println("b成员初始化块");
}
public b(){
system.out.println("b构造函数");
}
}
在代码里面我们总共有三个类,一个是做测试用的test4,一个是a,一个是a的子类b,我们在a和b类里面都有很多输出,一个是静态初始化的输出,一个是成员初始化的输出,一个是在构造函数里面的输出,从这些输出我们可以知道代码的执行顺序,以上代码运行输出如下:
a静态初始化块
b静态初始化块
a成员初始化块
a构造函数
b成员初始化块
b构造函数
a成员初始化块
a构造函数
b成员初始化块
b构造函数
从上面我们可以看出,a和b的静态初始化块只被执行了一次,也就是类的对象将要被生成的时候,它会执行,并且执行的顺序如下:父类的静态成员,子类的静态成员,父类的成员变量和构造方法,子类的成员变量和构造方法.当再用这个类生成对象的时候,静态的部份就不再被调用了.因为静态是类的所有实例所共享的,所以它在整个虚拟机的生命周期内只执行一次.
如果我们加上一个t.testclassforname("test1.b");放在main函数的最后面,我们会发现输出还是和刚刚一样,没有任何改变,这个时候,我们知道,当我们调用class.forname(name);的时候,类是不会自动初始化的,它默认只是把这个类的字节码读入内存,但是并没有初始化这个类.只有我们调用了newinstance()的时候,它才会被初始化.在这里我们再这样试一下:把a和b生成的class文件去掉,然后再分别调用class.forname和new b(),看看会怎么样,我们会发现当我们调用class.forname的时候,当我们要for的name找不到的时候,只会抛出classnotfoundexception,注意,它只是一个异常而已,而当我们new b()的时候,b的class文件却被我们删掉了,那就事大了,那就将抛出noclassdeffounderror,呵呵,它就是一个error了,这点区别我们可要注意啦,当我们在做这些事情的时候,一个只要捕获异常就可以了,一个却需要捕获一个error,一般来说,error级别的错误是不希望程序员去捕获的.了解了类的基本加载顺序以及加载机制后,对我们了解java是有一定的帮助的.