Java类加载器
来源:互联网 发布:数据工程师是干嘛的 编辑:程序博客网 时间:2024/06/05 19:01
Java中由类字节码流转化为JVM运行时类数据必须使用类加载器进行加载,Java中提供了三个类加载器:根类加载器,扩展类加载器,应用程序类加载器,使用的机制可以概括为“全盘负责双亲委托”机制。
注意图中的关系是委派关系,不是继承关系!源码中使用组合实现,即ClassLoader类的parent成员变量,而最上面的那个类加载器(根类加载器)的parent为null。
双亲委托机制在代码中具体体现在ClassLoader类的loadClass方法(下面是JDK1.8代码):
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //如果存在父类加载器则委托父类加载器去加载 if (parent != null) { c = parent.loadClass(name, false); //没有父类加载器,尝试委托根类加载器加载 } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } //上面流程委托加载失败,则使用当前加载器加载 if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //由类全限定名得到Class对象,自定义类加载器(仅)需要重写该方法 c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
自定义类加载器
public class MyClassLoader extends ClassLoader { public MyClassLoader() { } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { //这里类字节流来源为class文件 String path = "C:\\Users\\mao\\Desktop\\" + name + ".class"; //读取class文件,转化为字节流 byte[] b = IoUtils.getBytes(path); return defineClass(name, b, 0, b == null ? 0 : b.length); }}
这样就定义了一个自己的ClassLoader,接下来为测试代码,在C:\Users\mao\Desktop\路径下放一个String.class文件,然后使用该ClassLoader加载的一个class文件:
public class Test { public static void main(String[] args) throws Exception { //没有指定父类加载器,则会被默认设置为应用程序类加载器为父类加载器 ClassLoader cl = new MyClassLoader(); Class<?> clazz = Class.forName("String", true, cl); Object obj = clazz.newInstance(); System.out.println(obj); }}
代码打印:
I am a custom String class
因为我们放在C:\Users\mao\Desktop\路径下的String类的toString方法被重写了:
public class String { @Override public java.lang.String toString() { return "I am a custom String class"; }}
注意:这个String类是我们自己定义的,而JDK内部也有一个String类,运行时这两个类当然不是等价的,因此至少类加载器不同(当然上面的例子类全限定名也不同),而我们是无法做到把JDK的String类替换成我们自己定义的String类的(像上面的例子根类加载器会拒绝加载),这也说明了双亲委派机制的一个优点就是安全性高。
另外,Thread类有一个成员变量contextClassLoader,表示线程上下文类加载器,可以通过setContextClassLoader和getContextClassLoader方法设置和获取该变量的值,默认情况下contextClassLoader的值为父线程的contextClassLoader的值,而Java中最顶层的线程的contextClassLoader为应用程序类加载器。这个是在JDK1.2开始引入的,为了解决“顶层类”需要调用“底层类”却识别不了的问题。
- Java类加载器
- java类加载器
- java类加载器
- Java类加载器
- java类加载器
- Java类加载器
- Java 类加载器
- java类加载器
- java类加载器
- Java 类加载器
- -java 类加载器
- Java-类加载器
- Java类加载器
- Java 类加载器
- Java 类加载器
- java类加载器
- java类加载器
- Java-----类加载器
- 函数调用时函数栈状态分析
- gcc 怎样指定include路径
- Stomp协议学习与实战
- 简单的请求处理
- STM32固件库V3.5.0的CMSIS文件解析
- Java类加载器
- 多IDC的数据分布设计
- A compact algorithm for rectification of stereo pairs翻译,中文版
- 杭电1251——统计难题(字典树的应用)
- 新闻客户端的实现
- 代码段、数据段、堆栈段、数据段辨析
- 应用内跳转到系统设置界面
- Oil Deposits(水)
- Android 自定义标题栏TopBar