5接口初始化规则和类加载连接初始化案例剖析
Posted sunhao1234
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5接口初始化规则和类加载连接初始化案例剖析相关的知识,希望对你有一定的参考价值。
5.1、接口初始化规则
在了解接口的初始化规则前,先搞清类的初始化规则。
当java虚拟机初始化一个类时,会先初始化它的所有父类。但是这条规则并不适用于接口。
- 在初始化一个类时,并不会先初始化它所实现的接口;
- 在初始化一个接口时,并不会先初始化它的父接口;
使用一句话总结:实现类或者子接口的初始化并不会导致父接口的初始化。
只有当程序首次主动使用特定接口的静态变量(运行期常量)时,才会导致接口的初始化。这里需要注意的是接口中定义的变量都是常量,而常量又分为编译期常量和运行期常量,编译期常量的值在编译期间就可以确定,直接存储在了调用类的常量池中,所以访问接口中的编译期常量并不会导致接口的初始化,只有访问接口中的运行期常量才会引起接口的初始化。
下面通过代码验证上述结论:
package com.shtec.init; import java.util.UUID; /** * 在初始化一个类时,并不会先初始化它所实现的接口; * 在初始化一个接口时,并不会先初始化它的父接口; * @author sunhao * */ public class Demo3 { public static void main(String[] args) { //在初始化一个类时,并不会先初始化它所实现的接口; System.out.println(child3.a); //输出: 1 //没有输出“Parent3 invoked”,说明父接口Parent3并没有被初始化。 //在初始化一个接口时,并不会先初始化它的父接口; System.out.println(Parent3.str); //输出: //Parent3 invoked //a58ee35a-6590-416d-bf6b-ba6976f0d268 } } interface GrandPa{ //下面这段代码相当于普通类中的“静态代码块”,打印出来就相当于该接口被初始化了; public static Thread t = new Thread(){ { System.out.println("GrandPa invoked"); } }; } interface Parent3 extends GrandPa{ //运行期常量 String str = UUID.randomUUID().toString(); //下面这段代码相当于普通类中的“静态代码块”,打印出来就相当于该接口被初始化了; public static Thread t = new Thread(){ { System.out.println("Parent3 invoked"); } }; } class child3 implements Parent3{ public static int a = 1; }
5.2、类加载、连接、初始化案例剖析
下面使用两个案例复习一下类型的加载、连接和初始化过程;
package com.shtec.init; public class Demo4 { public static void main(String[] args) { System.out.println("a=" + Singleton.a); System.out.println("b=" + Singleton.b); //输出: //a=1 //b=1 } } //定义一个单例类 class Singleton{ public static int a; public static int b = 0; private static Singleton singleton = new Singleton(); private Singleton(){ a++; b++; } public static Singleton getInstance(){ return singleton; } }
如果对上面Demo4的代码输出没有疑问,请继续下面的代码示例:
package com.shtec.init; /** * 分析: * 将代码【public static int b = 0;】放在构造方法下面,输出结果为什么变了? * 请注意使用“类的加载、连接(验证、准备和解析)和初始化过程分析该案例”; * Singleton在初始化之前,会先经历连接阶段中的准备阶段,准备阶段会为类的【静态变量】分配内存,并将其初始化为【默认值】, * 此时,a=0;singleton=null,b=0; * 然后Singleton经历初始化阶段,代码自上而下执行,为类的静态变量赋予正确的初始值 * 此时,a=0; * singleton会创建一个对象,调用Singleton类的构造方法,此时a=1;b=1; * 接着初始化静态变量b,b的值又被更改为0; * 所以最终输出: * //a=1 * //b=0 * @author sunhao * */ public class Demo4 { public static void main(String[] args) { System.out.println("a=" + Singleton.a); System.out.println("b=" + Singleton.b); //输出: //a=1 //b=0 } } //定义一个单例类 class Singleton{ public static int a; private static Singleton singleton = new Singleton(); private Singleton(){ a++; b++; } public static int b = 0;//注意,本段代码调动了位置 public static Singleton getInstance(){ return singleton; } }
以上是关于5接口初始化规则和类加载连接初始化案例剖析的主要内容,如果未能解决你的问题,请参考以下文章
jvm之java类加载机制和类加载器(ClassLoader)的详解
Express实战 - 应用案例- realworld-API - 路由设计 - mongoose - 数据验证 - 密码加密 - 登录接口 - 身份认证 - token - 增删改查API(代码片段