Java类加载过程(1)

来源:互联网 发布:spss22数据分析教程 编辑:程序博客网 时间:2024/06/18 07:35
类加载机制
JVM吧class文件加载到内存,并对数据进行校验,解析和初始化,最终形成JVM可以直接使用的Java类型的过程
大致过程:
加载-->验证-->准备-->解析-->初始化-->使用-->卸载


加载:
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口,这个过程需要类加载器的参与


链接:
验证:确保加载的类信息符号JVM规范,没有安全方面的问题
准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配
解析:虚拟机常量池的符号引用替换为直接引用的过程


初始化:初始化阶段执行类构造器<clinit>()方法的过程,类构造器<clinit>()方法使用编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的
当初始化一个类的时候,如果发现其父类还没有初始化,则需要先执行父类的初始化
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步
当访问一个Java静态域时,只有真正声明这个域的类才会被初始化,只被初始化一次


类的主动引用(一定会发生类的初始化)
new一个类的对象
调用类的静态成员(除了final常量)和静态方法
使用java.lang.reflect包的方法对类进行反射调用
当虚拟机启动,java Hello,则一定会初始化Hello类,即先启动main方法所在的类
当初始化一个类,如果其父类没有初始化,则先会初始化他的父类


类的被动引用(不会发生类的初始化)
当访问一个静态域中,只有真正掌握这个域的类才会被初始化(通过子类引用父类的静态变量,不会导致子类初始化)
通过数组定义类的引用,不会触发此类的初始化
引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)


类加载器的作用
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法去类数据的访问入口


类缓存:
标准的Java SE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过,JVM垃圾收集器可以回收这些Class对象


类加载器的层次结构(这种层次结构是通过组合来实现的而不是通过继承的方式来实现)


引导类加载器(使用C写成的加载器):
用来加载Java核心库(JAVA_HOME/jre/lib/rt.jar或sun.boot.class.path路径下的内容),是用原生代码来实现的,并不继承自java.lang.ClassLoader
加载扩展类和应用程序类加载器,并制定他们的父加载器


扩展类加载器
用来加载Java的扩展器(JAVA_HOME/jre/ext/*.jar或java.ext.dirs路径下的内容)。java虚拟机的实现会提供一个扩展库目录,该类加载器在此目录里面查找并加载Java类
由sun.misc.Launcher$ExtClassLoader实现


应用程序类加载器
它根据Java应用的类路径(classpath,java.class.path),一般来说,Java应用的类都是由它来完成加载的
由sun.misc.Launcher$AppClassLoader实现


自定义类加载器
开发人员可以通过继承java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求
0 0
原创粉丝点击