吃透Java基础三:触发类初始化的五种方式

2024-09-03 01:48

本文主要是介绍吃透Java基础三:触发类初始化的五种方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一:类的生命周期

类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载七个阶段,其中验证、准备、解析这三个阶段统称为链接。
加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类加载过程必须按照这种顺序按部就班的开始。

二:类加载时机

什么情况下需要开始类加载过程的第一个阶段:加载 呢?Java虚拟机规范中并没有进行强制约束,这点可以交给虚拟机的具体实现来自由把握。
但是对于初始化阶段,虚拟机规范则是严格规定了有且只有如下五种情况必须对类进行“初始化”(而加载、验证、准备自然需要在此之前开始)

  1. 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
  2. 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
  3. 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
  4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
  5. 当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

对于这5钟会触发类进行初始化的场景,虚拟机规范中使用了一个很强烈的限定语:“有且只有”,这5种场景中的行为称为对一个类进行主动引用,下面我们来看一下。

1、使用new关键字

public class MyTest {public static void main(String[] args) {People people = new People();}public static class People {static {System.out.println("People 类被初始化");}}
}

运行输出:

People 类被初始化

2、调用本类静态变量或静态方法

public class MyTest {public static void main(String[] args) {People.getAge();}public static class People {static {System.out.println("People 类被初始化");}public static int age = 100;public static int getAge() {return age;}}
}

运行输出:

People 类被初始化

3、使用反射获取类信息

public class MyTest {public static void main(String[] args) {try {Class.forName("MyTest$People");} catch (ClassNotFoundException e) {e.printStackTrace();}}public static class People {static {System.out.println("People 类被初始化");}}
}

运行输出:

People 类被初始化

4、子类初始化时

public class MyTest {public static void main(String[] args) {Son son = new Son();}public static class People {static {System.out.println("People 类被初始化");}}public static class Son extends People {static {System.out.println("Son 类被初始化");}}
}

运行输出

People 类被初始化
Son 类被初始化

5、包含main()主函数的类

public class MyTest {static {System.out.println("MyTest 类被初始化");}public static void main(String[] args) {}
}

运行输出

MyTest 类被初始化

三:类的被动引用

除了上面5种引用类的方式称为主动引用方式之外的其它方式全是被动引用。被动引用不会触发类的初始化
我们看几个被动引用的例子

被动引用方式一:通过子类引用父类的静态字段,不会导致子类初始化

public class MyTest {public static void main(String[] args) {System.out.println(Son.a);}public static class Father {public static int a = 0;static {System.out.println("Father 类被初始化");}}public static class Son extends Father {static {System.out.println("Son 类被初始化");}}
}

输出结果

Father 类被初始化
0

被动引用方式二:通过数组定义来引用类,不会触发此类的初始化

public class MyTest {public static void main(String[] args) {Father[] fathers = new Father[10];}public static class Father {static {System.out.println("Father 类被初始化");}}
}

运行后什么也没输出

被动引用方式三:常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类初始化

public class MyTest {public static void main(String[] args) {System.out.println(Father.m);}public static class Father {static {System.out.println("Father 类被初始化");}public static final int m = 0;}
}

运行结果输出

0

这篇关于吃透Java基础三:触发类初始化的五种方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131683

相关文章

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

Mybatis官方生成器的使用方式

《Mybatis官方生成器的使用方式》本文详细介绍了MyBatisGenerator(MBG)的使用方法,通过实际代码示例展示了如何配置Maven插件来自动化生成MyBatis项目所需的实体类、Map... 目录1. MyBATis Generator 简介2. MyBatis Generator 的功能3

Spring MVC如何设置响应

《SpringMVC如何设置响应》本文介绍了如何在Spring框架中设置响应,并通过不同的注解返回静态页面、HTML片段和JSON数据,此外,还讲解了如何设置响应的状态码和Header... 目录1. 返回静态页面1.1 Spring 默认扫描路径1.2 @RestController2. 返回 html2

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

Spring核心思想之浅谈IoC容器与依赖倒置(DI)

《Spring核心思想之浅谈IoC容器与依赖倒置(DI)》文章介绍了Spring的IoC和DI机制,以及MyBatis的动态代理,通过注解和反射,Spring能够自动管理对象的创建和依赖注入,而MyB... 目录一、控制反转 IoC二、依赖倒置 DI1. 详细概念2. Spring 中 DI 的实现原理三、