千家信息网

如何理解Java JVM虚拟机中init和clinit的区别

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,如何理解Java JVM虚拟机中init和clinit的区别,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。:在jvm第一
千家信息网最后更新 2025年02月01日如何理解Java JVM虚拟机中init和clinit的区别

如何理解Java JVM虚拟机中init和clinit的区别,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

:在jvm第一次加载class文件时调用,包括静态变量初始化语句和静态块的执行。

:在实例创建出来的时候调用,包括调用new操作符;调用Class或Java.lang.reflect.Constructor对象的newInstance()方法;调用任何现有对象的clone()方法;通过java.io.ObjectInputStream类的getObject()方法反序列化。

是对象构造器方法,也就是说在程序执行 new 一个对象调用该对象类的 constructor 方法时才会执行init方法,而是类构造器方法,也就是在jvm进行类加载--验证--解析--初始化,中的初始化阶段jvm会调用clinit方法。

instance实例构造器,对非静态变量解析初始化,而clinit是class类构造器对静态变量,静态代码块进行初始化。是由javac添加的静态方法,并且在加载类之后由JVM调用。可以在类字节码中使用字节码大纲工具看到这种方法。注意,只有当一个类需要静态初始化时才添加,具体代码如下:

public class Test1 {

static int x = 1;

public static void main(String[] args) throws Exception {

}

}

public class Test2 {

static final int x = 1;

public static void main(String[] args) throws Exception {

}

}

Test1类中有,因为它的变量x需要使用1初始化;而Test2没有方法,因为它x是一个常数。还有一点是Class.forNameboolen intialize参数确定在加载后是否应该初始化类。

在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始化阶段是执行类构造器方法的过程

方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问如下代码

public class Test{

static{

i=0;//给变量赋值可以正常编译通过

System.out.print(i);//这句编译器会提示"非法向前引用"

}

static int i=1;

}

虚拟机JVM会保证在子类的方法执行之前,父类的方法已经执行完毕。 因此在虚拟机中第一个被执行的方法的类肯定是java.lang.Object。由于父类的方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作,如下代码中,字段B的值将会是2而不是1。

static class Parent{

public static int A=1;

static{

A=2;

}

static class Sub extends Parent{

public static int B = A;

}

public static void main(String[] args){

System.out.println(Sub.B);

}

}

注意:接口中属性都是static final类型的常量,在准备阶段就已经初始化完成了

接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此接口与类一样都会生成方法。 但接口与类不同的是,执行接口的方法不需要先执行父接口的方法。 只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的方法。

JVM类加载原理

1)类的生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)七个阶段

2)当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。

3)加载阶段:通过一个类的全限定名来获取此类的二进制字节流;将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;在java堆中生成一个代表这个类的Class对象,作为方法区这些数据的访问入口;

4)验证阶段:验证是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全;包括文件格式验证、元数据验证、字节码验证、符号引用验证;如果验证到输入的字节流不符合Class文件的存储格式,就抛出一个java.lang.VerifyError异常或其子类异常。

5)准备阶段:准备阶段是正式为类变量分配内存并设置类变量初始值(各数据类型的零值)的阶段,这些内存将在方法区中进行分配。

6) 解析阶段:解析阶段是在虚拟机将常量池内的符号引用替换为直接引用的过程。符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。直接引用:直接引用可以是直接指向目标的指针、相对偏移量或者一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在。

7)初始化阶段:初始化阶段是执行类构造器()方法的过程。

初始化是重点,需要清楚以下几点:

1)()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的。静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块中可以赋值,但是不能访问。

2) 方法与实例构造器()不同,不需要显示的调用父类构造器,虚拟机会保证在子类的()方法执行之前,父类的()已经执行完毕。

3)()方法对于类或接口来说不是必须的,如果一个类中没有静态语句块也没有对变量的赋值操作,那么编译器可以不为这个类生成()方法。

4)执行接口的()不需要先执行父接口的()方法,只有当父接口中定义的变量被使用时,父接口才会被初始化。接口的实现类在初始化时也不会执行接口的()方法。

5)虚拟机会保证一个类的()方法在多线程环境中被正确的加锁和同步,如果多个线程同时去初始化一个类,则只会有一个线程去执行这个类的()方法,其他线程需要阻塞等待。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。

方法 变量 静态 语句 接口 阶段 验证 构造器 符号 编译 对象 目标 编译器 准备 内存 是由 代码 数据 文件 程序 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 成都电子软件开发公司 烽火通信软件开发校招面试几轮 河北统一软件开发价格优惠 数据库安全国际标准有几级 最新网络安全法解读 测试工程师熟悉软件开发 升腾网络技术 jsp数据库操作数据库 跟对方加微信显示服务器异常 无线网络技术的改进方案 电商平台用什么类型数据库 方舟生存进化手机版炮塔服务器 中山专业服务器散热器订做 4u等服务器 反恐精英手游如何换服务器 服务器默认远程登录端口 人员管理系统软件开发费用 智慧工厂网络安全指哪些 专家解读网络安全会议 杭州分浪网络技术有限公司 数据库如何解决不可重复读 光遇红米手机的服务器是哪一个 linux下写到数据库表 电商公司用什么软件开发 网络安全知识证书下载 数据库工作者工资待遇 六安app软件开发定制 软件开发各阶段的作用 网络安全宣传电视 幼儿园中班网络安全论文
0