数组类的Class对象不是由classloader创建的,是由Java虚拟机在动态运行期间创建的
来自定义类加载器
loadclass方法会调用我们重写的findclass方法。findclass方法一定要重写
package com.kmoonwang.mywenda;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Random;
import java.util.UUID;
public class JVMlearning extends ClassLoader{
private String classLoaderName;
private final String fileExtension = ".class";
private String path;//指定从什么地方去加载
public void setPath(String path) {
this.path = path;
}
public JVMlearning(String classLoaderName){
super(); //将系统类加载器当作该类加载器的父加载器
this.classLoaderName = classLoaderName;
}
public JVMlearning(ClassLoader parent,String classLoaderName){
super(parent);//显示指定该类加载器的父加载器
this.classLoaderName = classLoaderName;
}
@Override
public String toString(){
return "[" + classLoaderName + "]";
}
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException{
System.out.println("findclass: "+className);
System.out.println("class loader name: "+ this.classLoaderName);
byte[] data = this.loadClassData(className);
return this.defineClass(className,data,0,data.length);
}
private byte[] loadClassData(String name){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null;
try{
name = name.replace(".","\\");
is = new FileInputStream(new File(this.path+name + fileExtension));
baos = new ByteArrayOutputStream();
int ch = 0;
while(-1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray();
}catch (Exception e){
e.printStackTrace();
}finally {
try{
is.close();
baos.close();
}catch (Exception e){
e.printStackTrace();
}
}
return data;
}
public static void main(String[] args) throws Exception{
JVMlearning loader1 = new JVMlearning("loader1");
loader1.setPath("C:\\Users\\Administrator\\Desktop\\");
Class<?> clazz = loader1.loadClass("com.kmoonwang.mywenda.Solution");
System.out.println("class1 hashcode: " + clazz.hashCode());
Object obj = clazz.newInstance();
System.out.println(obj);
System.out.println(obj.getClass().getClassLoader());
JVMlearning loader2 = new JVMlearning(loader1,"loader2");//loader2的父加载器是loader1
loader2.setPath("C:\\Users\\Administrator\\Desktop\\");
Class<?> clazz2 = loader2.loadClass("com.kmoonwang.mywenda.Solution");
System.out.println("class2 hashcode: " + clazz2.hashCode());
Object obj2 = clazz2.newInstance();
System.out.println(obj2);
System.out.println(obj.getClass().getClassLoader());
}
}
defineclass方法
但是loadclass方法的查找类的顺序是先查找已被加载过的类,然后去看父加载器是否能够加载,最后使用findClass方法进行加载
当工程中的Solution.class没有删除的时候,这个时候自定义类加载器是不会使用的,因为它的父亲-系统类加载器可以进行加载。只有当Solution.class删除的时候,它的父亲无法完成加载,这个时候才会使用自定义加载器。
在同一个命名空间中,类只被加载一次。
下面都是使用的系统类加载器进行加载,类只被加载一次
下面是有两个类加载器加载,所以加载了两次。
下面都是使用loader1完成的加载,所以类只被加载了一次
类加载器之间的关系不是继承关系,是包含关系,同一个类实例化创建的两个类加载器loader1,loader2.loader1可以成为loader2的父加载器
类的卸载
打印卸载信息:-XX:+TraceClassUnloading
但是类没有被初始化并不意味着类不会被加载,因为
继续改造程序
下面把MyCat的class文件删除,留下MySample的class文件。因为是系统类加载器加载的MySample,当他尝试去加载MyCat的时候就找不到然后报错了
把MySample的class文件删除,如下所示,MySample使用loader1进行加载,当用loader1加载MyCat的时候,会先使用它的父加载器,即系统加载器,系统加载器加载成功就是用它来加载。
系统类加载器是看不到他的子类加载器loader1加载过的MySample.class的