四、初识ClassLoader


双亲委派的定义

类加载器的父亲委托机制(双亲委派机制)

类加载器加载一个类时,会优先交给其父的加载器加载,父加载器找不到时会返回给子加载器

常用的类加载器包含以下

Bootstrap ClassLoader: 默认加载 rt.jar下的类,可以通过 -Xbootclasspath选项指定加载 jar包

Extension ClassLoader: 其包含 Bootstrap ClassLoader,默认加载 ext下的jar包 ,可以通过 -Djava.ext.dirs指定目录加载

App ClassLoader: 默认加载CLASSPATH,也可以加载-Djava.class.path所指定目录下的jar包

Customer ClassLoader: 通过ClassLoader自定义指定加载class


获取系统的ClassLoader以及其父的ClassLoader


通过打印的结果可以知道,BootStrapClassLoader是获取不到的,系统的ClassLoader为AppClassLoader,扩展ClassLoader为ExtClassLoader

获取ClassLoader的途径

获取ClassLoader的途径

获取当前类的ClassLoader    clazz.getClassLoader

获取当前线程上下文的ClassLoader    Thread.currentThread().getClassLoader();

获取系统的ClassLoader    ClassLoader.getSystemClassLoader

获取调用者的ClassLoader    DriverManager.getCallerClassLoader()


通过上面的结果可以得出以下结论:

默认情况下 线程上下文的类加载器为当前在加载线程的类的类加载器一致,即就是加载Test14类的加载器

获取class资源的URL,根据URL可以获取当前资源的完整路劲

获取数组的类加载器

以下段落来自doc文档

Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader.

这段话描述的意思为,如果是数组类型,那么数组类型的类加载器与数组里面的元素的类加载器一致,原生类型的话没有类加载器


String类型是有BootstrapClassLoader加载的,BootStrapClassLoader是获取不到的所以为空

Test15是由AppClassLoader加载的,所以test15s这个数组的类加载器也为AppClassLoader

原生类型数组的类加载器为空

自定义ClassLoader案列

public class Test16 extends ClassLoader {

    private String classLoaderName;

    private String fileExtention=".class";

    private String path;

    public String getPath() {

        return path;

    }

    public void setPath(String path) {

        this.path = path;

    }

    public Test16(String classLoaderName){

        //默认情况下,其父ClassLoader为getSystemClassLoader即AppClassLoader

        super();

        this.classLoaderName=classLoaderName;

    }

    public Test16(ClassLoader classLoader,String classLoaderName){

        //指定一个父的ClassLoader

        super(classLoader);

        this.classLoaderName=classLoaderName;

    }

    @Override

    public Class findClass(String name) throws ClassNotFoundException {

        System.out.println("find class invoked:"+name);

        System.out.println("class loader name:"+this.classLoaderName);

        byte []data=this.loadClassData(name);

        return this.defineClass(name,data,0,data.length);

    }

    private static void test(ClassLoader classLoader) throws Exception {

        Class clazz=classLoader.loadClass("test.Test13");

        Object object=clazz.newInstance();

        System.out.println(object);

    }

    private byte[] loadClassData(String name){

        InputStream in=null;

        byte []data=null;

        ByteArrayOutputStream baos=null;

        try {

            name=name.replace(".","/");

            in=new FileInputStream(new File(this.path+name+fileExtention));

            baos=new ByteArrayOutputStream();

            int ch=0;

            while((ch = in.read()) != -1){

                baos.write(ch);

            }

            data=baos.toByteArray();

            return data;

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            if(in != null){

                try {

                    in.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

            if(baos != null){

                try {

                    baos.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

        return null;

    }

}


可以发现并没有打印自定义ClassLoader中的findClass方法

原因为因为自定义的类加载Test16其父加载器为系统类加载器

当前工程下的class文件都是由系统类加载器加载的,所以不会执行自定义的类加载器定义的方法

删除classPath下的Test13,并且将Test13移到D盘的某个目录

执行下列的代码


可以发现执行了我们自定义的ClassLoader的findClass方法了

Class类的卸载

由用户自定义的类加载器所加载的类是可以被卸载的


通过制定-XX:TraceClassUnloading参数打印卸载信息


也可以通过jisualvm查看类的卸载信息



类加载器的命名空间

命名空间

每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成

在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的2个类

在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的2个类


通过上面的案列可以发现,2个不同的类加载器可以加载同一个包下的同一个类。


通过上面的案列可以发现,如果指定了父加载器为classLoader那么就不会执行自定义加载器的findClass方法了

因为类加载器加载类的时候会判断是否加载过,因为classLoader作为父类加载器已经加载过了

所以子加载器不会在次加载了


在运行期间,一个Java类是由该类的完全限定名(binary name,二进制名)和用于加载该类的定义类加载器(defining loader)所共同决定的。如果同样名字(即相同的限定名)的类是由两个不同的加载类所加载,那么这些类就是不同的,即便.class文件的字节码完全一样,并且从相同的位置加载也是如此。

类加载器命名空间的重要说明

关于命名空间的重要说明

1.子加载器加载的类能够访问父加载器加载的类

2.父加载器加载的类不能访问子加载器加载的类


发现并没有加载Cat


演示下列操作,此处省略图片,,最终得出上述关于命名空间的重要说明的结论

1.演示在classPath下删除 Sample.class,不删除Cat.class的效果 ,Sample会由Test16加载,Cat是由AppClassLoader加载

如果此时在Cat中获取Sample类会报错,所以此时 Test16可以访问 Cat,而Cat不能访问Sample

2.演示在classPath下删除 Cat.class,不删除Sample.class的效果  ,Sample会由AppClassLoader加载

此时因为Cat是在Sample内部初始化的 Cat必须也只能 AppClassLoader或者其父加载器加载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容

  • ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见...
    时待吾阅读 1,076评论 0 1
  • 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到...
    CHSmile阅读 1,598评论 0 12
  • JAVA类装载方式,有两种: 1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器...
    代码之尖阅读 655评论 0 48
  • ClassLoader 是 Java 届最为神秘的技术之一,无数人被它伤透了脑筋,摸不清门道究竟在哪里。网上的文章...
    MobMsg阅读 597评论 2 7
  • JVM类加载器ClassLoader JAVA类装载方式 1.隐式装载, 程序在运行过程中当碰到通过new 等方式...
    步二小哥阅读 436评论 0 1