加载 :指的是将编译好的class文件加载到内存中,并不局限于本地的class文件,也可以是是压缩文件,jar包,zip包,还可以从网络中加载。
class文件加载之后会以特定的结构存放在方法区中,jvm规范并没有规定以什么结构存储这些二进制的字节流,不同的虚拟机实现有不同的数据机构。二进制字节流存储到方法区之后,JVM会创建一个java.lang.Class对象,作为本类的外部访问接口,既然是对象就应该会存储到Java的堆中,但是JVM也并没有给出限制,HotPot虚拟机是存储在堆上的。
连接:连接分为三个步骤验证,准备和解析,但是需要注意的是不是就是这么个顺序,这三个步骤是交叉进行的。
《1》验证: 验证的目的是保证二进制字节流中的数据符合虚拟机规范,没有安全问题。
验证很重要且很耗时,但是他不到一定必要,如果代码已经被反复的验证和使用过,也可以手动地关闭,用于缩短类加载的时间, -Xverify:none 这个参数 可以关闭
验证的过程分为几个步骤:第一个就是文件格式的检查,包括魔数的验证,版本号检查等,实际上这一步是在加载的过程中发生的,只有这一步通过了才会存储到方法区中,后面的验证已经加载到方法区了。
第二步是语义检查,确保你的class文件符合Java规范
第三步是字节码验证,这一步最主要是的对方法体进行语义分析,确保方法再运行过程中不会危害虚拟机
最后一步是符号引用验证,这一步是在解析阶段,是对自身以外的引用的信息进行匹配和校验,确保解析工作能正常运行。
《2》准备: 准备阶段会做两件事,一个是为类的静态成员变量分配内存,第二个是为静态成员变量设置初始值,这里的初始值指的是默认值,比如int的默认值是0,真正的赋值是在初始化阶段进行的。因为class文件都是在方法区的,所以静态变量的空间也是分配在方法区的。
这里说的静态成员变量指的是static修饰的成员变量,final的静态变量会被初始化的,我看有的说final的静态变量不会在这里分配内存,而是已经在编译期间就被分配内存了,也不知道是我理解的不对还是咋地,编译阶段都没加载到内存呢,怎么分配空间,所以我感觉final的静态变量也是这个时候分配内存和初始化的。
《3》 解析。 这一步实际上替换引用,就是对字段,方法等的解析,会在本类,父类,接口等查找所引用的类等,将各个类直接联系起来
初始化:这是最后一步,到了这一步才开始真正执行定义的类中的代码,并完成静态变量值得设置,准备阶段已经设置了初始值,这一步则会进行默认值得设置。
静态代码块和静态变量虚拟机会为其生成一个同步方法clinit,同步方法是为了多线程安全问题,避免多次初始化。
类的加载与初始化时机:
加载这个并没有规定确切的时间,但是初始化一般是这几个时间:new一个对象的时候,静态变量的获取和赋值,静态方法的使用,反射调用的时候等,其实就是我们用到时候进行初始化。
类的加载需要类加载器:
类加载器分为启动类加载器,扩展类加载器,应用类加载器,还有是自定义了,自定义继承抽象类ClassLoader即可,需要实现findClass方法,将class文件记载到内存,然后用definClass方法再加载到内存的文件中查找需要的类即可。 类加载的过程中有个术语叫做双亲委派加载模型
本文暂时没有评论,来添加一个吧(●'◡'●)