类加载过程3个阶段:
1.加载
- 将类的字节码载入方法区,并创建.Class对象
- 加载符号引用到类常量池,只是有这个名字
- UnresolvedClass: $Name
- 如果类的父类没有加载,先加载父类
- 加载懒惰执行
2.链接
- 验证-验证类是否符合Class规范,合法性、安全性检查
- 准备-为static变量分配空间赋予默认值,和final修饰静态变量赋值。
- 解析-将常量池的符合引用解析为直接引用
- 把需要用到的符号引用进行初始化,变成直接的地址引用
- Class: Class xx.xxx.Test$Name @0x00000ac11
3.初始化
- 执行静态代码块与非final的静态变量赋值,或者被final修饰的引用类型
- 初始化是懒惰执行
准备阶段变量问题
类中的全局变量:
- 两次赋初始值的过程
- 一次是准备阶段:分配空间赋默认值,二次是初始化阶段:赋予由程序员在代码中定义的值。
- final 修饰的变量,直接分配空间赋初始值。
方法体中局部变量:
- 只有在初始化阶段赋值,如果没有赋值。就是不能使用的。
解析阶段引用解析问题
常见发生异常:
- NoSuchFieldError 根据继承关系从下往上,找不到相关字段
- IllegalAccessError:字段或方法访问权限不具备时。
- NoSuchMethodError:找不到相关方法错误。
初始化阶段成员变量问题
class A{
static int a=0;
static{
a=1;
b=1;
}
static int b=0;
main(){
System.out.println(a);
System.out.println(b);
}
}
- static语句块只能访问定义在static语句块之前的变量
- final static 修饰基本数据类型,会复制一份到需要的类中,调用时直接获取,不用经过定义它的原始类。
- JVM保证子类初始化方法执行前,父类的初始化方法已经执行完毕。
- 父类的static语句块优于子类的
- 父类构造方法优于子类的
双亲委派机制
类加载器:
- 一级类加载器 Bootstrap ClassLoader
- 二级类加载器 Extension ClassLoader
- 三级类加载器 Application ClassLoader
- 自定义类加载器
双亲委派:优先委派上级类加载器加载
- 如果上级类加载器能找到这个类,则由上级加载,加载后对下级加载器可见。
- 找不到这个类,则下级加载器才有权限加载。
哪些东西打破双亲委派机制
- Tomcat:Shared类加载器、WebApp类加载器、JSP类加载器
- WebAPPClassLoader加载自己目录下的.class文件,不会先交给Shared类加载器。
- 但是可以访问到Shared类加载器加载的类,实现共享和分离。
- SPI机制(Service Provider Interface):用于框架的扩展和替换组件
- 会在META-INF/services目录下创建一个接口全限定名为命名的文件,里面保存实现类的全限定名。
- 基于接口编程+策略模式+配置文件的动态加载机制,ServiceLoader动态加载。
- ServiceLoader最后采用当前线程上下文的类加载器。应用程序类加载器来加载第三方驱动。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)