`
jspengxue
  • 浏览: 178774 次
  • 性别: Icon_minigender_1
  • 来自: 天堂和地狱的中间
社区版块
存档分类
最新评论

java类加载机制

阅读更多
ClassLoader 是一个抽象类。为了扩充 Java 虚拟机动态装载类的方法,应用程序可实现 ClassLoader 的继承类。

通常,Java 虚拟机以与平台有关的方式,从局部文件系统中装载类。例如,在 UNIX 系统,虚拟机从 CLASSPATH 环境变量中定义的路径中装载类。

但是,

某些类可能不是来自文件,而是来自其它资源,诸如网络,或者它们可能是由应用程序创建的。

defineClass 方法将一字节数组转换为 Class 类的实例。采用 Class 类中的 newInstance 方法创建新定义的类的实例。

类装载器创建的方法和构造子可以引用其它类。为确定引用类,Java 虚拟机调用初始创建该类的类装载器的 loadClass 方法。如果 Java 虚拟机仅需确定此类是否存在,和如果存在则如何获知它的父类,那么将 resolve 标记设为 false。但是,如果该类的实例已创建,或它的方法已被调用,则必须解析该类。这种情况,resolve 标记设为 true,调用 resolveClass 方法。

例如,一个应用程序能够创建一网络类装载器,从某一个服务器上下载类文件。代码可能如下:

ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();
 . . . 
网络类装载器的子类必须定义 loadClass 方法,实现从网上下载类。一旦已下载完该类,就应使用 defineClass方法,创建它的一个实例。实现示例如下:


    
class NetworkClassLoader {
         String host;
         int port;
         Hashtable cache = new Hashtable();
         private byte loadClassData(String name)[] {
         // load the class data from the connection
          . . .
         }
         public synchronized Class loadClass(String name,
                                             boolean resolve) {
             Class c = cache.get(name);
             if (c == null) {
                 byte data[] = loadClassData(name);
                 c = defineClass(data, 0, data.length);
                 cache.put(name, c);
             }
             if (resolve)
                 resolveClass(c);
             return c;
         }
     }



Java的ClassLoader就是用来动态装载class的,ClassLoader对一个class只会装载一次,JVM使用的ClassLoader一共有4种:

启动类装载器,标准扩展类装载器,类路径装载器和网络类装载器。

这4种ClassLoader的优先级依次从高到低,使用所谓的“双亲委派模型”。确切地说,如果一个网络类装载器被请求装载一个java.lang.Integer,它会首先把请求发送给上一级的类路径装载器,如果返回已装载,则网络类装载器将不会装载这个java.lang.Integer,如果上一级的类路径装载器返回未装载,它才会装载java.lang.Integer。

类似的,类路径装载器收到请求后(无论是直接请求装载还是下一级的ClassLoader上传的请求),它也会先把请求发送到上一级的标准扩展类装载器,这样一层一层上传,于是启动类装载器优先级最高,如果它按照自己的方式找到了java.lang.Integer,则下面的ClassLoader都不能再装载java.lang.Integer,尽管你自己写了一个java.lang.Integer,试图取代核心库的java.lang.Integer是不可能的,因为自己写的这个类根本无法被下层的ClassLoader装载。

再说说Package权限。Java语言规定,在同一个包中的class,如果没有修饰符,默认为Package权限,包内的class都可以访问。但是这还不够准确。

确切的说,只有由同一个ClassLoader装载的class才具有以上的Package权限。

比如启动类装载器装载了java.lang.String,类路径装载器装载了我们自己写的java.lang.Test,它们不能互相访问对方具有Package权限的方法。

这样就阻止了恶意代码访问核心类的Package权限方法。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics