一、类加载过程
一个非数组类的加载阶段(加载阶段通过一个类的全限定名来获取描述此类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以去完成还可以自定义类加载器去控制字节流的获取方式(重写一个类加载器的 loadClass()
方法),这个动作放到Java虚拟机外部去实现。数组类型不通过类加载器创建,它由 Java 虚拟机直接创建。
类加载器用于实现类的加载动作。
二、
package JvmTest; import java.io.IOException; import java.io.InputStream; /* * 类加载器与instanceof关键字演示 * (1)Java序列化就是指把Java对象转换为字节序列的过程 * (2)Java反序列化就是指把字节序列恢复为Java对象的过程。 */ public class Nine { public static void main(String[] args) throws Exception{ //自己重写的类加载器 ClassLoader myLoader = new ClassLoader() { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { try{ //加载在同一路径下Class文件 String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; InputStream is = getClass().getResourceAsStream(fileName); if(is == null){ return super.loadClass(name); } //字节流读取 byte[] b = new byte[is.available()]; is.read(b); return defineClass(name, b, 0, b.length); // 把自己字节序列恢复成Java对象 }catch (IOException e){ throw new ClassNotFoundException(name); } } }; //使用myloader类加载去加载名为JvmTest.Nine的类,并实例化对象obj Object obj = myLoader.loadClass("JvmTest.Nine").newInstance(); System.out.println(obj.getClass()); //对象obj的确是类JvmTest.Nine实例化的对象
//instanceof Java中的一个双目运算符,用来测试一个对象是否为一个类的实例
System.out.println(obj instanceof JvmTest.Nine); //所属类检查,判断obj是否属于类 } }
class JvmTest.Nine false
上述代码重写了一个类加载器,使用这个类加载器去加载一个名为JvmTest.Nine的类,并创建了一个对象obj。结果发现obj的确是JvmTest.Nine的一个实例,但是做对象所属类检查的时候,却输出false。原因如下:
因为虚拟机出现了两个JvmTest.Nine类,一个是系统应用程序类加载器加载的,另一个是自定义myLoader类加载器加载的。虽然都来自同一个Class文件,但确实不同的独立的类。再次验证那句话:
即使两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那么这两个类就不相等。
三、双亲委派模型
从Java虚拟机的角度来讲,只存在两种不同的类加载器:
类加载器可以划分得更细致一些,主要分为以下三种:
类加载器的双亲委派模型
每一个类都有一个对应它的类加载器。系统中的ClassLoader在协同工作的时候会默认使用双亲委派模型:在类加载的时候,系统会首先判断当前类是否被加载过,已经被加载的类会直接返回,否则才会尝试加载。首先会把该请求委派父类加载器的loadClass()处理,因此所有的请求最终都应该传送到顶层的启动类加载器BootstrapClassLoader中。当父类加载器无法处理时,才由自己来处理。当父类加载器为null时,会使用启动类加载器BootstrapClassLoader作为父类加载器。流程图如下所示:
原文:https://www.cnblogs.com/xiazhenbin/p/14100069.html