类的加载机制
java虚拟机一般使用java类的流程:首先将开发者编写的java源代码编译成字节码文件,然后类加载器会读取字节码文件,并转换成java.lang.Class对象,java虚拟机利用反射方式创建真正的对象。类加载器多继承于ClassLoader类。
类加载器
- BootstarpClassLoader启动类加载器, 加载JAVA_HOME/jre/lib的jar包
- EXTensionClassLoader扩展类加载器,加载JAVA_HOME/jre/lib/ext的jar包
- ApplicationClassLoader应用类加载器,加载CLASSPATH下的jar包。
双亲委派模型工作过程
- 当前类加载器从自己已经加载的类中查询此类是否已经加载,如果加载,返回已经加载的类。(避免重复加载)
- 如果没有找到,就委托父类去加载,父类加载也是先查看自己已经加载的类中此类是否已经加载,有就返回,没有继续委托他的父类去加载,直到委托到启动类加载器为止,如果父类加载器为空了,就代表启动类加载器作为父类去加载了,所以String类型的返回类加载器为null。
- 如果启动类加载器也失败,就使用扩展类加载器,继续失败则使用应用类加载器,继续失败则抛出异常ClassNotFoundException。
使用双亲委派的好处
- 避免用户自己编写的类注入替换Java的核心类。不使用的话,用户自定义的类可以替代Java核心API中定义的类,可能被黑客将病毒代码写入自定义的String类中,然后加载到jvm上,会对jvm产生病毒攻击
- 避免类的重复加载,jvm判定两个类是否是同一个类不仅是判断两个类类名是否相同,还需要判断两个类是否是同一个类加载器加载的。
类的加载过程
- 加载
- 先通过类加载器查找字节码文件
- 加载字节码文件之后生成相应的Class对象
- 链接
- 验证: 验证当前Class对象是否能在当前JVM内存上运行(版本号问题)
- 准备: 为类的静态变量分配内存并设定初始值
- 解析: 虚拟机将常量池内的符号引用替换为直接引用的过程
如果当前类有父类,重复以上操作(如果是一连串继承下来的类,运行起来会特别慢就是这个原因)
- 初始化
- 对类的静态变量进行赋值的过程