Java的类装载器(Class Loader)

from: http://blog.bcchinese.net/shiaohuazhang/archive/2004/10/13/2715.aspx

1.类装载器的功能及分类

功能:类装载器是用来把类(class)装载进JVM的

分类:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)。

1)bootstrap是JVM自带的类装载器,用来装载核心类库,如java.lang.*等。由例1可以看出,java.lang.Object是由bootstrap装载的。

2). 扩展(extensions)类加载器,扩展类加载器负责加载扩展路径下的代码,一般位于<JAVA_HOME>/jre/lib/ext  或者通过java.ext.dirs 这个系统属性指定的路径下的代码。这个类加载器是由sun.misc.Launcher$ExtClassLoader 实现的。


3)System Class Loader是一个特殊的用户自定义类装载器,由JVM的实现者提供,
   在编程者不特别指定装载器的情况下默认装载用户类。
   系统类装载器可以通过ClassLoader.getSystemClassLoader() 方法得到。


4)用户自定义的Class Loader,继承ClassLoader.

bootstrap<---ExtClassLoader<---AppClassLoader   (父子关系)
======================

例1,测试你所使用的JVM的ClassLoader

package com.test.app;

public class LoaderSample1 {   
public static void main(String[] args) {       
Class c;        ClassLoader cl;
cl = ClassLoader.getSystemClassLoader();       
System.out.println(cl);
while (cl != null) {           
cl = cl.getParent();           
System.out.println(cl);       
}
try {      
c = Class.forName("java.lang.Object");        
cl = c.getClassLoader();       
System.out.println("java.lang.Object's loader is " + cl);     
c = Class.forName("LoaderSample1");     
cl = c.getClassLoader();     
System.out.println("LoaderSample1's loader is " + cl);     
} catch (Exception e) {         
e.printStackTrace();      
}   
}
}
在我的机器上(Sun Java 1.6)的运行结果

sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$ExtClassLoader@addbf1
null
java.lang.Object's loader is null
LoaderSample1's loader is sun.misc.Launcher$AppClassLoader@19821f

第一行表示,系统类装载器实例化自类sun.misc.Launcher$AppClassLoader

第二行表示,系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader

第三行表示,系统类装载器parent的parent为bootstrap

第四行表示,核心类java.lang.Object是由bootstrap装载的

第五行表示,用户类LoaderSample1是由系统类装载器装载的

============================


2.parent delegation模型

从1.2版本开始,Java引入了双亲委托模型,从而更好的保证Java平台的安全。
在此模型下,当一个装载器被请求装载某个类时,它首先委托自己的parent去装载,
若parent能装载,则返回这个类所对应的Class对象,若parent不能装载,则由parent的请求者去装载。 

自己写的加载器类的父类是AppClassLoader



 

3.命名空间及其作用
每个类装载器有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。
不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的reference,还是可以访问另一命名空间的类。
=============================
package com.test.app;

import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;


public class LoaderSample2 {
public static void main(String[] args) {       
try {           
String path = System.getProperty("user.dir");    
URL[] us = {new URL("file://" + path + "/subapp/")};  
ClassLoader loader = new URLClassLoader(us);       
Class c = loader.loadClass("com.test.app.subapp.LoaderSample3"); 
Object o = c.newInstance(); 
Field f = c.getField("age");      
int age = f.getInt(o);   
System.out.println("age is " + age);
} catch (Exception e) {     
e.printStackTrace();     
}  
}
}
===============
package com.test.app.subapp;

public class LoaderSample3 {
static {       
System.out.println("LoaderSample3 loaded");   
}  
public int age = 30;
}
====================




4.运行时包(runtime package)

由同一类装载器定义装载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,
不仅要看它们的包名是否相同,还要看的定义类装载器是否相同。只有属于同一运行时包的类才能互相访问包可见的类和成员。
这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类java.lang.Yes,
并用用户自定义的类装载器装载,由于java.lang.Yes和核心类库java.lang.*由不同的装载器装载,它们属于不同的运行时包,
所以java.lang.Yes不能访问核心类库java.lang中类的包可见的成员。

5.类的更新

类被加载后,但是又发生了修改,被重新编译了。是否原来的类能从加载器中删除?比如jsp变化了,服务端JVM需要更新这个类。但是其实是弄出一个新的加载器实例来加载这个class文件。至于什么时候卸载旧的class文件则由JVM自己来处理。

 

6.动态加载

 //具体的类名可以是从配置文件读取的,这样就实现了动态的加载,修改配置文件就可以加载不同的实现类,

//必须重新编译类,newInstance: 弱类型。低效率。只能调用无参构造。 

 Class c=Class.forName("fromXmljavaname").newInstance();

 

//通过反射机制可以实现复杂一些的类的动态加载

Class c=Class.forName("fromXmljavaname").

//通过反射调用类的getInstance完成实例化
 Method m=c.getMethod("getInstance", String.class);
 Test t=(Test)m.invoke(null, "abc");//getInstance是static,应该第一个参数为null,否则需要被调类的实例对象

 


总结:

简单讨论了类装载器,parent delegation模型,命名空间,运行时包.

命名空间并没有完全禁止属于不同空间的类的互相访问,双亲委托模型加强了Java的安全,运行时包增加了对包可见成员的保护。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值