一、自定义类加载器在复杂类情况下的运行分析
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