| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1106 人关注过本帖
标题:[分享]JAVA类加载以及反射机制
只看楼主 加入收藏
狂放不羁
Rank: 4
等 级:贵宾
威 望:12
帖 子:925
专家分:0
注 册:2007-1-24
收藏
 问题点数:0 回复次数:8 
[分享]JAVA类加载以及反射机制

JAVA中的类文件是动态的加载到内存中的。因为JVM指令是被封装在了. class文件里面,而.class文件的加载过程是动态的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。这里所说的用到包括两种方式,第一种就是new一个对象的时候(这个时候要特别注意,当设计到多态的时候,就会有一点点变化,这时候编译器会做一些优化,这样以来当加载的时候会提前加载设计到多态的类,关于这一点下面有个例子(example 1)来说明。另一种就是当一个类的静态代码被调用的时候。


java 代码

//example 1
// Zoo.java

abstract class Animal {

Animal(){

System.out.println("Animal constructor");
}
}

class Tiger extends Animal {

Tiger(){

System.out.println("Tig constructor ");
}

}

class Dog extends Animal {

Dog(){

System.out.println("Dog Constructor ");
}
}

public class Zoo {

private Animal am; //Example 1.1
//private Dog am; Example 1.2
private Tiger tiger;

Zoo(){
tiger = new Tiger();
am = new Dog();

}


public static void main(String [] args){

System.out.println("new Zoo before");
Zoo z = new Zoo();
System.out.println("new Zoo after ");

}
}


运行此测试程序结果如Example1.1图 :
Example 1.1

当我们注释掉Example.1.1行时,运行Example1.2行,结果如下:

Example 1.2

分析以上两图的运行结果我们可以看出:当我们将子类对象赋值给父类时,编译器会做一点优化,于是加载器在还没有new 子类对象的时候已经加载了父类以及子类(example1.1结果),当不存在多态的时候,我们可以看到是当要new Dog()的时候才会加载Dog以及父类。无论何种方式,在new之前,类确实已经加载到了内存中。


JAVA为我们提供了两种动态机制。第一种是隐式机制。其实new一个对象和调用类的静态方法时,就是隐式机制在工作。第二种是显示机制。显示的机制又有两种策略(第一种是用java.lang.Class的forName(String str)方法,第二种是用java.lang.ClassLoader的loadClass())。

第一种:利用forName方法
当我们查API文档就会发现forName方法有两种形式。分别如下:
public static Class<?> forName(String className)
throws ClassNotFoundException


public static Class<?> forName(String name,
boolean initialize,
ClassLoader loader)
throws ClassNotFoundException

先来说说第二种方法:第二个方法值得注意的就是第二个参数boolean initialize,如果我们把这个参数设置为false,那么当我们加载完类后就不会执行静态代码和静态的初始化动作。只有当我们new一个对象的时候才会初始化。而第三个参数是用来指明类的加载器的。
如果查看java.lang.Class类的源代码,上述两种方法最终都会调用Class类中的私有的native方法forName0(),此方法的声明如下:
private static native Class forName0(String name, boolean init , ClassLoader loader)
throws ClassNotFoundException;

所以当我们调用Class.forName(name )时,其实是在方法内部调用了:
forName0(name, true, ClassLoader.getCallerClassLoader());
当我们调用Class.forName(name, initialize, loader )的时候,实际上此方法内部调用了:
forName0(name, initialize, loader);
下面看一个例子,如果方法中第二个参数为false的情况:


java 代码
//example 2.1
// Zoo.java

abstract class Animal {

static {

System.out.println("Animal static code block ");
}
Animal(){

System.out.println("Animal constructor");
}
}

class Tiger extends Animal {

Tiger(){

System.out.println("Tig constructor ");
}

}

class Dog extends Animal {

Dog(){

System.out.println("Dog Constructor ");
}
}

public class Zoo {


public static void main(String [] args)throws Exception {

System.out.println("new Zoo before");
Zoo z = new Zoo();
Class c = Class.forName("Dog",false,z.getClass().getClassLoader());
System.out.println("initilize before ");
Animal dog = (Animal)c.newInstance();
System.out.println("new Zoo after ");

}
}


Example 2.1

从上图可以看出来类加载完成后并没有立即执行静态初始化代码,而是到了实例化的时候才进行了静态初始化。有时候我们会说静态代码是在类第一次被加载时执行的,并且只执行一次。其实这是对与new一个对象,第一次访问类的静态代码以及第二个参数为true时而言的,对于动态的加载来说,如果forName方法的第二个参数设置为false,那么就是在实例化的时候才会执行静态初始化。当然默认情况下第二个参数是true.

第二种方法:利用Class对象获取的ClassLoader装载。

下面是一个简单的例子:


java 代码
//Example 2.2
//Zoo.java
abstract class Animal {

static {

System.out.println("Animal static code block ");
}
Animal(){

System.out.println("Animal constructor");
}
}

class Tiger extends Animal {

Tiger(){

System.out.println("Tig constructor ");
}

}

class Dog extends Animal {

Dog(){

System.out.println("Dog Constructor ");
}
}

public class Zoo {


public static void main(String [] args)throws Exception {


Class c = Zoo.class;
ClassLoader loader = c.getClassLoader();
System.out.println("loader before");
Class dog = loader.loadClass("Dog");
System.out.println("instance before ");
Animal an = (Animal)dog.newInstance();



}
}


Example 2.2

从上图可以看出loader完成以后并没有立即进行静态代码的执行。只有当newInstance()的时候才执行静态初始化,这和把
public static Class forName(String name, boolean initialize, ClassLoader loader)的第二个参数指定为false的情况完全一样。其实每当我们写完一个编译单元以后就会得到一个.calss文件,这个文件中就包含了该类的Class对象。JVM就是利用这个class对象来进行动态装载类的。

example1.1
图片附件: 游客没有浏览图片的权限,请 登录注册

example1.2
图片附件: 游客没有浏览图片的权限,请 登录注册

example2.1
图片附件: 游客没有浏览图片的权限,请 登录注册

example2.2
图片附件: 游客没有浏览图片的权限,请 登录注册

[此贴子已经被作者于2007-8-28 22:35:10编辑过]

搜索更多相关主题的帖子: 加载 JAVA 内存 机制 多态 
2007-08-28 20:25
狂放不羁
Rank: 4
等 级:贵宾
威 望:12
帖 子:925
专家分:0
注 册:2007-1-24
收藏
得分:0 

总结了一下JAVA中的动态加载类的机制。。希望对初学者有点帮助。。

2007-08-28 20:36
老小吴
Rank: 1
等 级:新手上路
帖 子:42
专家分:0
注 册:2007-8-9
收藏
得分:0 

十分严重的顶


努力的笨小孩
2007-08-28 22:40
jdk2006
Rank: 1
等 级:新手上路
帖 子:244
专家分:0
注 册:2007-5-12
收藏
得分:0 

小弟,收到,顶////////


2007-08-30 16:37
神vLinux飘飘
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:浙江杭州
等 级:贵宾
威 望:91
帖 子:6140
专家分:217
注 册:2004-7-17
收藏
得分:0 
呵呵~~~

淘宝杜琨
2007-08-30 20:16
jiazhaoq
Rank: 1
等 级:新手上路
帖 子:17
专家分:0
注 册:2007-9-12
收藏
得分:0 
很不错的顶!!
2007-09-20 10:42
hwoarangzk
Rank: 4
来 自:冰封王座
等 级:贵宾
威 望:12
帖 子:1894
专家分:0
注 册:2007-7-17
收藏
得分:0 
最近在看java核心技术就看到这里,顶了!

I'm here, as always...
2007-09-20 10:58
千里冰封
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:灌水之王
等 级:版主
威 望:155
帖 子:28477
专家分:59
注 册:2006-2-26
收藏
得分:0 
这一块是很重要的,如果你想深入JAVA的话

可惜不是你,陪我到最后
2007-09-20 11:52
hwoarangzk
Rank: 4
来 自:冰封王座
等 级:贵宾
威 望:12
帖 子:1894
专家分:0
注 册:2007-7-17
收藏
得分:0 
不过感觉好难啊,抽象了

I'm here, as always...
2007-09-20 12:00
快速回复:[分享]JAVA类加载以及反射机制
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.019736 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved