服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

进阶:javaclassloader与package机制

为了深入了解java的classloader机制,我们先来做以下实验:

package java.lang;
public class test {
    public static void main(string[] args) {
        char[] c = "1234567890".tochararray();
        string s = new string(0, 10, c);
    }
}

string类有一个package权限的构造函数string(int offset, int length, char[] array),按照默认的访问权限,由于test属于java.lang包,因此理论上应该可以访问string的这个构造函数。编译通过!执行时结果如下:

exception in thread "main" java.lang.securityexception: prohibited package name:
 java.lang
        at java.lang.classloader.defineclass(unknown source)
        at java.security.secureclassloader.defineclass(unknown source)
        at java.net.urlclassloader.defineclass(unknown source)
        at java.net.urlclassloader.access$100(unknown source)
        at java.net.urlclassloader$1.run(unknown source)
        at java.security.accesscontroller.doprivileged(native method)
        at java.net.urlclassloader.findclass(unknown source)
        at java.lang.classloader.loadclass(unknown source)
        at sun.misc.launcher$appclassloader.loadclass(unknown source)
        at java.lang.classloader.loadclass(unknown source)
        at java.lang.classloader.loadclassinternal(unknown source)

奇怪吧?要弄清为什么会有securityexception,就必须搞清楚classloader的机制。

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权限方法。


扫描关注微信公众号