兴文县建设工程网站,如何将网站添加到域名,长沙网站设计费用,深圳网站公司招聘信息Java类加载机制的全过程#xff1a; 加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的#xff0c;类型的加载过程必须按照这种顺序按部就班地开始#xff0c;而解析阶段则不一定#xff1a;它在某些情况下可以在初始化阶段之后再开始#xff0c; 这是为了支持Java…Java类加载机制的全过程 加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的类型的加载过程必须按照这种顺序按部就班地开始而解析阶段则不一定它在某些情况下可以在初始化阶段之后再开始 这是为了支持Java语言的运行时绑定特性也称为动态绑定或晚期绑定。
1、加载Loading ”加载“是”类加载“的一个阶段再这个阶段Java虚拟机需要完成三件事
通过一个类的全限定名来获取定义此类的二进制字节流。将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。再堆中生成一个代表这个类的Class对象作为方法区这个类的各种数据的访问入口。
就是将 java的字节码文件(.Class文件加载到内存当中然后在方法区当中根据这个文件构建这个类的类模型这个类包含了从字节码文件中解析出来的常量池、类方法、等信息。然后再堆中生成这个java.lang.Class对象用来封装方法区内的类模型的数据结构。反射就是通过这个Class对象提供的接口去访问方法区中的数据模型。类加载器完成Class 类的构造方法是私有的只有 JVM 能够创建。
数组情况有些不同数组类本身不是通过类加载器完成而是由Java虚拟机直接再内存中动态构造出来。数组内的元素是通过类的加载器完成的。
2、连接Linking 2.1 验证Verification 验证是连接阶段的第一步这一步骤是为了确保Class文件的字节流包含的信息符合规范确保这些信息再运行后不会危害虚拟机自身安全。
2.1.1、文件格式验证 这提阶段要验证的字节流是否符合Class文件格式规范并且能被当前版本虚拟机处理例如是否以魔数0xCAFEBABE开头主、次版本号是否在当前Java虚拟机接受范围之内等等。只有经过哟了这部分的验证之后字节流才能进入到方法区当中去储存后面三个验证阶段则是再方法区进行的。
2.1.2、元数据验证元数据描述数据的数据。 这个部分是对字节码描述信息进行语义分析如这个类是否有父类这个类的父类是否有继承了不被允许的类、抽象方法是否有实现等等看看有没有错误。
2.1.3、字节码验证 字节码验证也是验证过程中最为复杂的一个过程。它试图通过对字节码流的分析判断字节码是否可以被正确地执行。比如在字节码的执行过程中是否会跳转到一条不存在的指令。函数的调用是否传递了正确类型的参数。变量的赋值是不是给了正确的数据类型等。 如果一个类型中有方法体的字节码没有通过字节码验证那它肯定是有问题的但如果一个方法 体通过了字节码验证也仍然不能保证它一定就是安全的。即使字节码验证阶段中进行了再大量、再 严密的检查也依然不能保证这一点。
2.1.4、符号引用验证 最后一个阶段的校验行为发生在虚拟机将符号引用转化为直接引用[3]的时候这个转化动作将在 连接的第三阶段——解析阶段中发生。符号引用验证可以看作是对类自身以外常量池中的各种符号 引用的各类信息进行匹配性校验通俗来说就是该类是否缺少或者被禁止访问它依赖的某些外部 类、方法、字段等资源。本阶段通常需要校验下列内容
符号引用中通过字符串描述的全限定名是否能找到对应的类。在指定类中是否存在符合方法的字段描述符及简单名称所描述的方法和字段。 ....... 就是检查你写的类内依赖的其他类的信息能不能用会不会找不到或者没有权限等。 2.2 准备Preparation 准备阶段是正式为类中定义的变量静态变量分配内存并设置类变量的初始值阶段。这些变量所使用的内存再方法区JKD7即以前用永久代实现JDK8及以后由元空间实现。此时这个赋初值并不是我们写的哪些初始化操作例如 public static int a 333再准备阶段a的值并不是333而是0这里的赋初值是赋零值。 注意
这里不包含基本数据类型的字段用 static final 修饰的情况因为 final 在编译的时候就会分配了。注意这里不会为实例变量分配初始化类变量会分配在方法区中而实例变量是会随着对象一起分配到 Java 堆中在这个阶段不会像初始化阶段中那样会有初始化或者代码被执行。 2.3 解析Resolution 符号引用 符号引用以一组符号来描述所引用的目标符号可以是任何 形式的字面量只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关引 用的目标并不一定是已经加载到虚拟机内存当中的内容。 直接引用 直接引用是可以直接指向目标的指针、相对偏移量或者是一个能 间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局直接相关的同一个符号引用在不同虚 拟机实例上翻译出来的直接引用一般不会相同。 所谓解析就是将符号引用转为直接引用。也就是得到类、字段、方法在内存中的指针或者偏移量。因此可以说如果直接引用存在那么可以肯定系统中存在该类、方法或者字段。但只存在符号引用不能确定系统中一定存在该结构。
3、初始化Initialization 初始化阶段是类加载的最后一个步骤再之前的加载阶段中处理加载阶段可以用用户子自定义类加载器的方式参与其他时候都是由JVM自己主导控制的到了初始化阶段才正式的使用我们自己写的java代码了再这个阶段有一个执行类构造器方法需要我们去了解clinit()方法这个给方法并不是我们编写的而是javac编译器自动生成的。 clinit()方法方法是由编译器自动收集类中所有的类变量(static)的赋值动作和静态语句块合并而成的。
那类什么是进行初始化呢以下情况都是还未被初始化
使用new关键字实例化对象的时候。读取或设置一个类型的静态字段被final修饰、已在编译期把结果放入常量池的静态字段除外的时候。调用一个类型的静态方法的时候。使用java.lang.reflect包的方法对类型进行反射调用的时候。如果类型没有进行过初始化则需 要先触发其初始化。当初始化类的时候如果发现其父类还没有进行过初始化则需要先触发其父类的初始化。当虚拟机启动时用户需要指定一个要执行的主类包含main()方法的那个类虚拟机会先 初始化这个主类。当使用JDK 7新加入的动态语言支持时如果一个java.lang.invoke.MethodHandle实例最后的解 析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句柄并且这个方法句柄对应的类没有进行过初始化则需要先触发其初始化。当一个接口中定义了JDK 8新加入的默认方法被default关键字修饰的接口方法时如果有 这个接口的实现类发生了初始化那该接口要在其之前被初始化。
并不是只要这个类的代码出现就一定会被初始化当被动使用时就不会出现初始化。
子类调用父类的静态字段不会引起子类的初始化。当有数组People[] a new People();初始化时他并不会初始化而是一个虚拟机自动生成的数组类进行初始化。引用定义再某个类内的常量被static final修饰的也不会引起这个类的初始化因为这个常量再编译阶段就已经存入调用类的常量池中了。