转自:http://carl-java.iteye.com/blog/978680
java中class.forName和classLoader都可用来对类进行加载。前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数,创建类的对象
事例代码如下:
1.使用classLoader加载
System.out.println("before loadClass... ");
Class c =Test.class.getClassLoader().loadClass("com.hundsun.test.ClassInfo");
System.out.println("after loadClass... ");
System.out.println("before newInstance... ");
ClassInfo info1 =(ClassInfo) c.newInstance();
System.out.println("after newInstance... ");
输出结果:
before loadClass...
after loadClass...
before newInstance...
static invoked...
contruct invoked...
after newInstance...
2.使用class.forName进行加载
System.out.println("before class.forName");
Class cc =Class.forName("com.hundsun.test.ClassInfo");
System.out.println("after class.forName");
ClassInfo info2 =(ClassInfo) cc.newInstance();
输出结果:
before class.forName
static invoked...
after class.forName
before newInstance...
contruct invoked...
after newInstance...
下面说一下两者具体的执行过程
LoadClass()方法加载类及初始化过程:
类加载(loadclass())(加载)——》newInstance()(链接+初始化)
newInstance():
(开始连接)静态代码块——》普通变量分配准备(a=0;b=0;c=null)——》(开始初始化)普通变量赋值(a=1;b=2;c=”haha”)——》构造方法——》初始化成功。
Class.forName(Stirng className)一个参数方法加载类及初始化过程:
类加载(Class.forName())(加载)——》静态代码块——》newInstance()(链接+初始化)
newInstance():
(开始连接)普通变量分配准备(a=0;b=0;c=null)——》(开始初始化)普通变量赋值(a=1;b=2;c=”haha”)——》构造方法——》初始化成功。
Class.forName()三个参数的加载类及初始化过程同classLoader一样。
从上边的断点调试可以看出,静态代码块不是在初始化阶段完成的,它陷于类初始化,先于普通变量默认分配(整型分配为0,字符串分配为null),这也就是为什么我们不能在静态代码块中引用普通变量的原因之一,这与上面所谓的“分配”、“初始化”相违背。
所以我觉得JVM的类加载及初始化过程应该是这样的。
1. 类加载:Bootstrap Loader——》Extended Loader——》System Loader
2. 静态代码块初始化
3. 链接:
a) 验证:是否符合java规范
b) 准备:默认初始值
c) 解析:符号引用转为直接引用,解析地址
4. 初始化
a) 赋值:java代码中的初始值
b) 构造:构造函数