github地址:
https://github.com/lishanglei/jvm_study.git
当一个类被加载、验证、准备、解析、初始化后,它的声明周期就开始了。当该类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,该类再方法去的数据也会被卸载,从而结束该类的生命周期。
一个类合适结束生命周期,取决于代表它的Class对象何时结束生命周期
由java虚拟机自带的类加载器(跟加载器bootstrap、扩展类加载器extension、系统加载器system)所加载的类,在虚拟机的生命周期中,始终不会被卸载。java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用他们所加载的类的Class对象,因此这些Class对象始终是可触及的
用户自定义的类加载器所加载的类是可以被卸载的
用户自定义类加载器loader1加载MyTest1类,在类加载器的内部实现中,用一个java集合来存放所加载类的引用。另一方面,一个Class对象总是会引用它的类加载器,调用Class对象的getClassLoader()方法,就能获取它的类加载器。由此可见,MyTest1类的Class实例和loader1之间为双向关联关系
一个类的实例总是引用代表这个类的Class对象。在Object类中定义了getClass()方法,这个方法返回代表对象所属类的Class对象的引用。此外,所有的Java类都有一个静态属性class,它引用代表这个类的Class对象
public class MyTest16_1 extends ClassLoader{
private String classLoaderName;
private final String fileExtension = ".class";
//加载类的路径
private String path;
public void setPath(String path) {
this.path = path;
}
/**
* @param classLoaderName 类加载器的名字
* <p>
* Creates a new class loader using the <tt>ClassLoader</tt> returned by
* the method {@link #getSystemClassLoader()
* <tt>getSystemClassLoader()</tt>} as the parent class loader.
*/
public MyTest16_1(String classLoaderName) {
//将系统类加载器当作该类加载器的父类加载器
super();
this.classLoaderName = classLoaderName;
}
public MyTest16_1(ClassLoader parentClassLoader, String classLoaderName) {
//显示指定该类加载器的父类加载器
super(parentClassLoader);
this.classLoaderName = classLoaderName;
}
/**
* 根据二进制的类的名字查找类,并返回其Class对象
*
* @param className
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
System.out.println("findClass invoked");
byte[] data = this.loadClassData(className);
//将字节数组转化为类的Class对象
return this.defineClass(className, data, 0, data.length);
}
/**
* 根据类的名字返回类数据的字节数组
*
* @param clasaName
* @return
*/
private byte[] loadClassData(String clasaName) {
System.out.println("loadClassData invoked");
InputStream in = null;
byte[] data = null;
ByteArrayOutputStream baos = null;
clasaName = clasaName.replace(".", "\\");
try {
in = new FileInputStream(new File(this.path + clasaName + this.fileExtension));
baos = new ByteArrayOutputStream();
int ch = 0;
while (-1 != (ch = in.read())) {
baos.write(ch);
}
data = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
@Override
public String toString() {
return "[ " + this.classLoaderName + " ]";
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
MyTest16_1 loader1 = new MyTest16_1("loader1");
//loader1.setPath("D:\\mingbyte\\jvm_study\\target\\classes");
loader1.setPath("C:\\Users\\10025\\Desktop\\");
Class<?> aClass = loader1.loadClass("com.jvm.class_loader.MyTest1");
//根据类的Class对象生成一个实例
Object o = aClass.newInstance();
System.out.println("o 的类加载器: " + o.getClass().getClassLoader());
loader1=null;
aClass=null;
o=null;
System.gc();
//将loader1的引用指向一个新的对象
loader1 =new MyTest16_1("loader2");
loader1.setPath("C:\\Users\\10025\\Desktop\\");
Class<?> clazz = loader1.loadClass("com.jvm.class_loader.MyTest1");
//根据类的Class对象生成一个实例
Object o1 = clazz.newInstance();
System.out.println("o1 的类加载器: " + o1.getClass().getClassLoader());
}
}
输出结果:
findClass invoked
loadClassData invoked
o 的类加载器: [ loader1 ]
[Unloading class com.jvm.class_loader.MyTest1 0x00000007c0061028]
findClass invoked
loadClassData invoked
o1 的类加载器: [ loader2 ]
结果分析:
在JVM命令中添加指令 -XX:+TraceClassUnloading 将类卸载信息打印出来