一、自定义类加载器在复杂类情况下的运行分析

1、使用之前创建的类加载器

public class MyTest16  extends  ClassLoader{

    private String className;

    //目录
private String path; private final String fileExtension = ".class"; public MyTest16(String classLoadName){
super(); //将系统类加载器当做该类加载器的父加载器
this.className = classLoadName;
} public MyTest16(ClassLoader parent, String classLoadName){
super(parent); //显示指定该类加载器的父加载器器
this.className = classLoadName;
} public void setPath(String path) {
this.path = path;
} @Override
public String toString() {
return "[" + this.className + "]";
} @Override
protected Class<?> findClass(String clasName) throws ClassNotFoundException {
System.out.println("findClass invoked:" + clasName);
System.out.println("class loader name: " + this.className);
byte[] data = this.loadClassData(clasName);
return this.defineClass(clasName,data, 0, data.length);
} private byte[] loadClassData(String className){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null; try{
className = className.replace(".","//");
//System.out.println("className:" +this.className);
is = new FileInputStream(new File(this.path + className + this.fileExtension));
baos = new ByteArrayOutputStream();
int ch = 0;
while ( -1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray(); }catch (Exception ex){
ex.printStackTrace();
}finally {
try {
is.close();
baos.close();
}catch (Exception ex){
ex.printStackTrace();
}
} return data; } }

  

2、创建MyCat类

public class MyCat {
public MyCat(){
System.out.println("MyCat is loaded by:" + this.getClass().getClassLoader());
}
}

  

3、创建MySample类

public class MySample {

    public MySample(){
System.out.println("MySample is loaded by:" + this.getClass().getClassLoader());
new MyCat(); }
}

  

4、创建测试类

public class MyTest17 {
public static void main(String[] args) throws Exception{
MyTest16 loader1 = new MyTest16("loader1"); Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MySample"); System.out.println("class:" + clazz.hashCode()); //如果注释掉改行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
//因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加重MyCat Class
Object object = clazz.newInstance(); }
}

  

打印结果

class:1735600054
MySample is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2

  

增加-XX:+TraceClassLoading后的打印结果

如果去掉Object object = clazz.newInstance();

打印结果为

说明:如果注释掉Object object = clazz.newInstance();该行,那么并不会实例化MySample对象,即MySample构造方法不会被调用

因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加载MyCat Class。

         而且这个例子说明MyCat没有被预先加载

二、对一的Code进行改造

在一的基础上,新建一个测试类

public class MyTest17_1 {
public static void main(String[] args) throws Exception{
MyTest16 loader1 = new MyTest16("loader1");
loader1.setPath("D:/temp/");
Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MySample"); System.out.println("class:" + clazz.hashCode()); //如果注释掉该行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
//因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加载MyCat Class
Object object = clazz.newInstance(); }
}

  里面增加了一个方法loader1.setPath("D:/temp/");

然后将MyCat.class 和MySample.class 剪切到D:/temp/目录下,如下面两图

打印结果:

findClass invoked:com.example.jvm.classloader.MySample
class loader name: loader1
class:2133927002
MySample is loaded by:[loader1]
findClass invoked:com.example.jvm.classloader.MyCat
class loader name: loader1
MyCat is loaded by:[loader1]

  

三、类加载命名空间

在二的基础上,MyCat.java 增加一行代码System.out.println("from MyCat:" + MySample.class);

public class MyCat {
public MyCat(){
System.out.println("MyCat is loaded by:" + this.getClass().getClassLoader()); System.out.println("from MyCat:" + MySample.class);
}
}

  然后重新build,打印结果如下:

class:1735600054
MySample is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
from MyCat:class com.example.jvm.classloader.MySample

  

现在将build路径下的classloader文件夹拷贝到D:\temp\com\example\jvm\classloader下,删除build路径下的MySample.class

打印输出结果:

findClass invoked:com.example.jvm.classloader.MySample
class loader name: loader1
class:2133927002
MySample is loaded by:[loader1]
MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/jvm/classloader/MySample
at com.example.jvm.classloader.MyCat.<init>(MyCat.java:10)
at com.example.jvm.classloader.MySample.<init>(MySample.java:10)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at com.example.jvm.classloader.MyTest17_1.main(MyTest17_1.java:16)
Caused by: java.lang.ClassNotFoundException: com.example.jvm.classloader.MySample
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 8 more

  说明:MySample由自定义loader加载,MyCat由AppClassLoader。两个类是不同的loader加载,处于不同的命名空间。

所以System.out.println("from MyCat:" + MySample.class); 抛出异常。 子加载器所加载的类能够访问父加载器所加载的类。反之,父加载器所加载的类无法访问子加载器所加载的类

  

JVM 自定义类加载器在复杂类情况下的运行分析的更多相关文章

  1. JVM自定义类加载器加载指定classPath下的所有class及jar

    一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...

  2. (转)JVM——自定义类加载器

    背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...

  3. JVM——自定义类加载器

    )以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理.这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着 ...

  4. JVM 自定义类加载器

    一.创建自定义类加载器 package com.example.jvm.classloader; import java.io.ByteArrayOutputStream; import java.i ...

  5. 4.自定义类加载器实现及在tomcat中的应用

    了解了类加载器的双亲委派机制, 也知道了双亲委派机制的原理,接下来就是检验我们学习是否扎实了,来自定义一个类加载器 一. 回顾类加载器的原理 还是这张图,类加载器的入口是c++调用java代码创建了J ...

  6. jvm(1)类的加载(二)(自定义类加载器)

    [深入Java虚拟机]之四:类加载机制 1,从Java虚拟机的角度,只存在两种不同的类加载器: 1,启动类加载器:它使用C++实现(这里仅限于Hotspot,也就是JDK1.5之后默认的虚拟机,有其他 ...

  7. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  8. JVM性能优化--类加载器,手动实现类的热加载

    一.类加载的机制的层次结构 每个编写的".java"拓展名类文件都存储着需要执行的程序逻辑,这些".java"文件经过Java编译器编译成拓展名为". ...

  9. 【Java虚拟机8】自定义类加载器、类加载器命名空间、类的卸载

    前言 学习类加载器就一定要自己实现一个类加载器,今天就从一个简单的自定义类加载器说起. 自定义类加载器 例1 一个简单的类加载器,从一个给定的二进制名字读取一个字节码文件的内容,然后生成对应的clas ...

随机推荐

  1. Python JSON的简单使用

    1          json简介 1.1         json是什么? JSON(JavaScript Object Notation)是一种轻量级的数据交换格式. “在JSON出现之前,大家一 ...

  2. Linux命令——lspci

    参考:7 Linux lspci Command Examples to Get PCI Bus Hardware Device Info 简介 lspci可以看成“ls” + “pci”.lspci ...

  3. 大数据技术之Hadoop3.1.2版本伪分布式部署

    大数据技术之Hadoop3.1.2版本伪分布式部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.主机环境准备 1>.操作系统环境 [root@node101.yinzh ...

  4. visual studio故障修复

    如果没有安装程序,直接在控制面板——>程序和功能,在列表中找到您安装的vs,右键选择更改,然后程序会启动,做一些准备.然后又三个选项,可以选择修复.

  5. netty websocket

    1 全局保存websocket的通道  NettyConfig.java public class NettyConfig { public static ChannelGroup group = n ...

  6. linux系统编程之文件与io(二)

    今天继续学习文件与io,话不多说,开始进入正题: 文件的read和write系统调用: 说明:函数中出现在size_t和ssize_t是针对系统定制的数据类型:     下面以一个实现文件简单拷贝的示 ...

  7. 《你说对就队》第九次团队作业:【Beta】Scrum meeting 3

    <你说对就队>第九次团队作业:[Beta]Scrum meeting 3 项目 内容 这个作业属于哪个课程 [教师博客主页链接] 这个作业的要求在哪里 [作业链接地址] 团队名称 < ...

  8. flask框架下读取mysql数据 转换成json格式API

    研究了一天 因为需要从数据库拿数据然后转换成json的格式 expose出去为 API 发现一条数据是容易,两条以上我居然搞了这么久 好歹出来了 先贴一下 后面更新 mysql的操作 比较容易了htt ...

  9. php 常用字符串函数总结

    php里面自带的字符串函数,日期函数,数组函数等,有时候可以帮助我们解决很复杂的问题,运用起来也比较简单. 下面总结了一下常用的字符串函数. addcslashes — 为字符串里面的部分字符添加反斜 ...

  10. linux第三天

    一.用户的类型   1.root管理员:所有权限(r w x)   2.文件拥有者(u):谁创建谁拥有   3.组 (g):用户组   4.其它用户(o):不属于用户组,也不是文件的创建者,不是管理员 ...