`

java反射中class.forName和classLoader加载类的区分

 
阅读更多

  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) 构造:构造函数 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics