一、自定义类加载器在复杂类情况下的运行分析
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]
原文:https://www.cnblogs.com/linlf03/p/11027293.html