demo类
public class Test2 { static { System.out.println("静态初始化块执行了!"); } }
分别切换加载方式 , 会有不同的输出结果 。
Class.forName()和ClassLoader.loadClass()区别
Class.forName():将类的.class文件加载到jvm中之外 , 还会对类进行解释 , 执行类中的static块;
ClassLoader.loadClass():只干一件事情 , 就是将.class文件加载到jvm中 , 不会执行static中的内容,只有在newInstance才会去执行static块 。
注:
Class.forName(name, initialize, loader)带参函数也可控制是否加载static块 。并且只有调用了newInstance()方法采用调用构造函数 , 创建类的对象。
5、双亲委派模型
双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求 , 它首先不会自己去尝试加载这个类 , 而是把请求委托给父加载器去完成 , 依次向上 , 因此 , 所有的类加载请求最终都应该被传递到顶层的启动类加载器中 , 只有当父加载器在它的搜索范围中没有找到所需的类时 , 即无法完成该加载 , 子加载器才会尝试自己去加载该类 。
双亲委派机制
1、当AppClassLoader加载一个class时 , 它首先不会自己去尝试加载这个类 , 而是把类加载请求委派给父类加载器ExtClassLoader去完成 。
2、当ExtClassLoader加载一个class时 , 它首先也不会自己去尝试加载这个类 , 而是把类加载请求委派给BootStrapClassLoader去完成 。
3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class) , 会使用ExtClassLoader来尝试加载;
4、若ExtClassLoader也加载失败 , 则会使用AppClassLoader来加载 , 如果AppClassLoader也加载失败 , 则会报出异常ClassNotFoundException 。
ClassLoader源码分析:
public Class<?> loadClass(String name)throws ClassNotFoundException { return loadClass(name, false); } protected synchronized Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException { // 首先判断该类型是否已经被加载 Class c = findLoadedClass(name); if (c == null) { //如果没有被加载 , 就委托给父类加载或者委派给启动类加载器加载 try { if (parent != null) { //如果存在父类加载器 , 就委派给父类加载器加载 c = parent.loadClass(name, false); } else { //如果不存在父类加载器 , 就检查是否是由启动类加载器加载的类 , 通过调用本地方法native Class findBootstrapClass(String name) c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { // 如果父类加载器和启动类加载器都不能完成加载任务 , 才调用自身的加载功能 c = findClass(name); } } if (resolve) { resolveClass(c); } return c; }
双亲委派模型意义:
-系统类防止内存中出现多份同样的字节码
-保证Java程序安全稳定运行
6、自定义类加载器
通常情况下 , 我们都是直接使用系统类加载器 。但是 , 有的时候 , 我们也需要自定义类加载器 。比如应用是通过网络来传输 Java 类的字节码 , 为保证安全性 , 这些字节码经过了加密处理 , 这时系统类加载器就无法对其进行加载 , 这样则需要自定义类加载器来实现 。自定义类加载器一般都是继承自 ClassLoader 类 , 从上面对 loadClass 方法来分析来看 , 我们只需要重写 findClass 方法即可 。下面我们通过一个示例来演示自定义类加载器的流程:
package com.neo.classloader; import java.io.*; public class MyClassLoader extends ClassLoader { private String root; protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = https://www.isolves.com/it/cxkf/yy/JAVA/2019-09-12/loadClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] loadClassData(String className) { String fileName = root + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; try { InputStream ins = new FileInputStream(fileName); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int length = 0; while ((length = ins.read(buffer)) != -1) { baos.write(buffer, 0, length); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } public String getRoot() { return root; } public void setRoot(String root) { this.root = root; } public static void main(String[] args) { MyClassLoader classLoader = new MyClassLoader(); classLoader.setRoot("E:/temp"); Class
推荐阅读
- 人工智能算法是如何从数据中学习规律的
- 提高 JavaScript 性能的 12 个技巧
- 汽车淹了怎么办 汽车淹水熄火怎么办
- 解密电商系统架构发展历程
- 螃蟹要倒过来蒸吗 螃蟹蒸的时候要翻过来吗
- 只要10分钟,教你配置出炫酷的数据可视化大屏
- PHP五十个提升执行效率的小技巧,和常见问题
- 超详细的MySQL数据库字符集总结
- Python pip的自动更新升级失败问题解决方案
- 全面解析下Spring Boot操作Redis的几种方案