一. Java类加载步骤
(1) Java加载.class文件后到类生成,消亡经历了什么过程 ?
- 加载
- 验证 : 验证.class文件中的内容是否符合jvm虚拟机规范
准备 : 开辟内存空间来存储这个类和其类变量(就是内部的static变量), 为对象的成员变量赋"0"值
解析 -
初始化 :
- 如果该类有父类, 先加载, 验证, 解析父类
- 再对成员变量赋代码这种声明的真正的值
- 使用
- 卸载
(2) 什么时候会加载.class文件
当使用到某个类时, 类加载器会对.class文件进行加载,验证,准备,解析,初始化,使用
二. 类加载器和双亲委派机制
2.1 Java中的类加载器分类(依据.class文件的位置不同划分)
-
BootStrap加载器
负责加载$JAVA_HOME/lib
目录下的jar包, 或通过-Xbootclasspath
指定路径下的jar包 -
Extension加载器
负责加载$JAVA_HOME/lib/ext
目录下的jar包 -
Application加载器
加载$classpath
里的类, 直到applicaiton加载器, 才是加载自己写的代码 -
自定义类加载器
2.2 类加载器的双亲委派机制
- Java类加载器时层级结构
如上所述, java的类加载器时分层的, 形成了自顶向下的亲子结构.
classloader.png
-
类加载器的双亲委派机制
- 每层的类加载器都会优先让父一级的类加载器加载.如果父一级的加载器找不到.class文件, 再由自己加载.
- 双亲委派机制, 并不是强制性要求, 而是jvm设计者推荐的一种类加载方式. 这种做法的好处是, 无论是哪个类加载器加载的.class文件, 最终都会被指派给同一个祖先类加载器加载
-
JVM在搜索类的时候,又是如何判定两个class是相同的呢?
两个类的类名
和类加载器
都一样时, jvm才判定这事同一个类 -
线程的
context class loader
和 普通的类 classloader
有什么不同
Thread.currentThread().getContextClassLoader(); - 线程的上下文类加载器
this.getClass().getClassLoader(); - 类的类加载器
有一个规则 : 每个类都是用自己的 classLoader 去加载其他类. 假若 ClassA.class 引用了 ClassB.class, 那么 ClassB 需要在 ClassA 的 classLoader 的 classpath 下; 线程上下文类加载器
是当前线程的 classLoader. 如果一个对象由 classLoaderC 创建传给了 classLoaderD 拥有的线程下使用, 则该对象要想使用自己的 classLoader 加载不到的资源时, 就要使用 Thread.currentThread().getContextClassLoader()
加载
- spark 中加载 "hive-site.xml" 的方式
Option(Thread.currentThread().getContextClassLoader).getOrElse(getSparkClassLoader)
def getSparkClassLoader: ClassLoader = getClass.getClassLoader
网友评论