前言
每一个类加载器都有各自的命名空间,命名空间是由该加载器及其所有父加载器所构成的,因此在每个类加载器中同一个class都是独一无二的。
public class NameSpace {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader classLoader = NameSpace.class.getClassLoader();
Class<?> aClass = classLoader.loadClass("fast.cloud.nacos.juc.classloader.HelloWorld");
Class<?> bClass = classLoader.loadClass("fast.cloud.nacos.juc.classloader.HelloWorld");
System.out.println(aClass.hashCode());
System.out.println(bClass.hashCode());
System.out.println(aClass == bClass);
}
}
不论load多少次,你都将会发现他们始终是同一份class对象。但是使用不同类加载器,或者同一个类加载器的不同实例,去加载同一个class,则会在堆内存和方法区会产生多个class对象。
不同类加载器加载同一个class
public class DiffClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
MyClassloader myClassloader = new MyClassloader();
BrokerDelegateClassLoader brokerDelegateClassLoader = new BrokerDelegateClassLoader();
Class<?> clazzA = myClassloader.loadClass("fast.cloud.nacos.juc.classloader.HelloWorld");
Class<?> clazzB = brokerDelegateClassLoader.loadClass("fast.cloud.nacos.juc.classloader.HelloWorld");
System.out.println(clazzA.getClassLoader());
System.out.println(clazzB.getClassLoader());
System.out.println(clazzA.hashCode());
System.out.println(clazzB.hashCode());
System.out.println(clazzA == clazzB);
}
}
会生成两个class实例。
相同类加载器加载同一个class
public class DoubleClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
BrokerDelegateClassLoader myClassloaderA = new BrokerDelegateClassLoader();
BrokerDelegateClassLoader myClassloaderB = new BrokerDelegateClassLoader();
Class<?> clazzA = myClassloaderA.loadClass("fast.cloud.nacos.juc.classloader.HelloWorld");
Class<?> clazzB = myClassloaderB.loadClass("fast.cloud.nacos.juc.classloader.HelloWorld");
System.out.println(clazzA.getClassLoader());
System.out.println(clazzB.getClassLoader());
System.out.println(clazzA.hashCode());
System.out.println(clazzB.hashCode());
System.out.println(clazzA == clazzB);
}
}
会生成两个class实例。首先通过加载记录表中的也就是缓存中的,查看该类是否已经被加载过了,如果加载过了,就不会重复加载了,否则将会认为其实首次加载,也就是说同一个class实例在同一个类加载器命名空间之下是唯一的。
类的卸载
类的卸载需要满足下面三个条件才会被GC回收,也就是类被卸载。
- 该类所有的实例都已经被GC
- 加载该类的ClassLoader实例被回收
- 该类的class实例没有在其他地方被引用。