类加载器实战剖析与疑难点解析

对于类加载器之前有这样一张图,回顾一下:

也就是不同的类加载器其加载的具体目录是不一样的,那能否通过代码将这些类加载器所加载的目录打印出来直观的感受一下?当然可以,下面就来尝试一下:

编译运行:

/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/classes
/Users/xiongwei/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/tools.jar:/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes

【注意】:因为我是在mac上运行的,所以目录与目录之间的间隔以“:”分隔。

其中可以看一下应用类加载器所加载的目录中能看到咱们工程的目录,如下:

了解了各个类加载器真正的加载目录之后,下面具体来做一些实验来进一步对这些类加载器有一个更深刻的认识:

那有木有办法让系统的根类加载器来加载MyTest1呢?试一下呗,要想让根类加载器加载,那肯定得将MyTest1.class放置到根类加载器所加载的目录处才行嘛,而根类加载器涉及到的目录还挺多的,咱们就找一个相关的目录就行,这里找最后输出的这个,如下:

“/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/classes”,那到命名窗口先定位到这个目录下呗:

那往上退一级呢?

少了这个文件夹咱创建一个嘛,当然这里是系统目录需要root权限,所以如下:

为了方便起见将咱们工程当中的所有.class复制到这个目录底下~

难道得要加权限,试试:

好~~~接下来程序完全不用变,再次运行:

好~~还是将创建的classes还原,以勉影响默认根类加载器的行为,如下:

此时如果再运行则就由咱们自己所定义的loader1加载了:

接下来再来看一下扩展类加载器,哪个类默认是由扩展类加载器所加载的呢,下面演示一下:

关于AESKeyGenerator是什么这里暂且不需要关心,只需观察它的类加载器既可,下面运行看一下:

我们知道根类加载器是从这个系统属性设置的目录来寻找的,如下:

那如果咱们手动来将这个属性的目录值给改成其它目录,那还能正确加载AESKeyGenerator这个类么,下面试验一下:

因为当前目录是不存在AESKeyGenerator这个类的当然就找不到喽,挺神奇的。

接下来再做另外一个实验,先新建一个类:

编译运行:

因为都是由应用类加载器所加载的嘛,所以尽量loader1和loader2是不同的加载器,但是都会委托给同一个它的父加载器应用类加载器所加载。

编译运行:

程序是可以正常运行的。那写它有啥意义呢?这是为了之后的进一步改造会有一个比较惊奇的结果而做准备的,下一次继续。

posted on 2018-06-08 21:26  cexo  阅读(294)  评论(0编辑  收藏  举报

导航