本文是笔者在学习Java 类加载的过程当中,整理的心得体会,共勉!java
简单概念:网络
将Java类的.class文件中的二进制数据读入到内存中,放置在运行时数据区的方法区内。jvm
何时会进行类加载?函数
本地系统加载;学习
代理加载,好比Spring的AOP动态代理;测试
从jar包中加载;this
等等等等加密
ClassLoader是一个抽象类,核心方法以下:spa
defineClass():目的是将byte字节流解析成JVM可以识别的Class对象。命令行
findClass():此方法支持重载,与defineClass()配合使用,目的是获取Class对象的字节码。这个方法的意义在于,咱们不只仅能够经过class文件实例化对象,也能够经过其余方式,好比从网络上获取的字节码文件,可能会有对应的加密规则。
loadClass():此方法支持重载,目的是获取加载类的类对象。
resolveClass():实现让JVM连接这个类,此方法调用的是本地方法,不能重载。
今生命周期对应到ClassLoader类的具体方法:
加载:loadClass()、findClass()、defineClass()
链接:包括验证、准备、解析:resolveClass() 本地native方法
初始化:JVM负责
概念介绍:
大体的ClassLoader分类:
心得体会:
这里的父加载器与子加载器 在java类关系上并非继承关系;
实现本身的类加载器,不论是直接实现抽象类ClassLoader,仍是继承其余子类,父加载器都是AppClassLoader;
一、命令行启动应用时候由JVM初始化加载
二、经过Class.forName()方法动态加载
三、经过ClassLoader.loadClass()方法动态加载
Class.forName()和ClassLoader.loadClass()区别
Class.forName():将类的.class文件加载到jvm中以外,还会对类进行解释,执行类中的static块;
ClassLoader.loadClass():只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
Class.forName(name,initialize,loader)带参函数也可控制是否加载static块。而且只有调用了newInstance()方法采用调用构造函数,建立类的对象
基于上面对于类加载器的分析,自定义ClassLoader的状况以下:
从上面的分析咱们还能够获得,自定义ClassLoader的实现思路能够经过继承ClassLoader类,重写findClass()来实现,固然你也能够重写loadClass(),可是默认的loadClass()是实现类加载双亲委托模式的,除非你想要破坏这种双亲委托模式,否则就别重写了。
下面是我在本机写的测试自定义ClassLoader的Demo:
/** * 自定义路径下的class文件加载 * @Auther: trey_stao@163.com * @Date: 2018/5/31 19:34 * @Description: */ public class PathClassLoader extends ClassLoader { private String classPath; public PathClassLoader(String classPath) { this.classPath = classPath; } private String packageName = "com.trey.classloader.Test"; protected Class<?> findClass(String name) throws ClassNotFoundException { if(packageName.startsWith(name)) { byte[] classData = getData(name); if(classData == null) { throw new ClassNotFoundException(); } else { System.out.println("当前类加载器:"+this.getClass().getClassLoader().toString()); return defineClass(name, classData, 0, classData.length); } } else { return super.loadClass(name); } } private byte[] getData(String name) { String path = classPath + File.separatorChar + name.replace('.',File.separatorChar) + ".class"; try { InputStream is = new FileInputStream(path); ByteArrayOutputStream stream = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int num = 0; while ((num = is.read(buffer)) != -1) { stream.write(buffer, 0, num); } return stream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } }
这是给本身布置的对类加载学习的总结练习。下面说下本身准备实现的思路:
整理这篇学习心得时,参考了一些文章,特在此注明,表示感谢!
周志明:《深刻理解Java虚拟机:JVM高级特性与最佳实践》
纯洁的微笑:java类的加载机制
许令波:《深刻分析Java Web 技术内幕》