首页 > 编程语言 >Java的类加载

Java的类加载

时间:2024-11-19 13:47:45浏览次数:3  
标签:初始化 Java 字节 验证 static public 加载

1. 加载的时机 (加载阶段虚拟机需要完成3件事)

在这里插入图片描述

a. 通过一个类的全限定名来获取定义此类的二进制字节流	
b. 将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构
c.在内存中生成一个代表这个类的java.lang.Class对象,作业方法区这个类的各种数据的访问入口

2.验证

a.文件格式验证
这阶段的验证是基于二进制字节流进行的,只有通过了这个阶段的验证之后,这段字节流才被允许进人 Java 虚拟机内存的方法区中进行存储,所以后面 的三个验证阶段全部是基于方法区的存储结构(内存)上进行的,不会再直接读取、操作字节流了。
b.元数据验证
元数据验证是验证的第二阶段,主要目的是对类的元数据信息进行语义校验,保证不存在与《Java 语言规范》定义相悖的元数据信息。
c.字节码验证
如果一个类型中有方法体的字节码没有通过字节码验证,那它肯定是有问题的
d.符号引用验证
符号引用验证的主要目的是确保解析行为能正常执行,如果无法通过符号引用验证,将会抛出异常。
e.验证(总结)
验证阶段对于虚拟机的类加载机制来说,是一个非常重要的、 但却不是必须要执行的阶段,因为验证阶段只有通过或者不通过的差别,只要通过了验证,(包括自己编写的、第三方包中的、从外部加载的、动态生成的等所有代码)都已经被反复 使用和验证过,在生产环境的实施阶段就可以考虑使用-Xverify:none 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。其后就对程序运行期没有任何影响了。如果程序运行的全部代码

初始化

初始化主要是对一个 class 中的 static{}语句进行操作(对应字节码就是 clinit 方法)。 <clinit>()方法对于类或接口来说并不是必需的,如果一个类中没有静态语句块,也没有对变量的赋值操作,那么编译器可以不为这个类生成<clinit >()方法。 初始化阶段,虚拟机规范则是严格规定了有且只有 6 种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始):

  1. 遇到 new、getstatic、putstatic 或 invokestatic 这 4 条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这 4 条指令的最常见的 Java 代码场景是:

    • 使用 new 关键字实例化对象的时候。
    • 读取或设置一个类的静态字段(被 final 修饰、已在编译期把结果放入常量池的静态字段除外)的时候
    • 调用一个类的静态方法的时候。
  2. 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

  3. 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

  4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含 main()方法的那个类),虚拟机会先初始化这个主类。

  5. 当使用 JDK 1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法 句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

  6. 当一个接口中定义了 JDK1.8 新加入的默认方法(被 default 关键字修饰的接口方法)时,如果这个接口的实现类发生了初始化,那该接口要在其之前 被初始化。

测试案例

/**
 * 父类
 */
public class SuperClazz {
   static     {
      System.out.println("SuperClass init!");
   }
   public static int value=123;
   public static final String HELLOWORLD="hello king";
   public static final int WHAT = value;
}


/**
 * 子类
 */
public class SubClaszz extends SuperClazz {
   static{
      System.out.println("SubClass init!");
   }

}


/**
 *初始化的各种场景
 * 通过VM参数可以观察操作是否会导致子类的加载 -XX:+TraceClassLoading
 **/
public class aaa {
    public static void main(String[]args){
        Initialization initialization = new Initialization();
        initialization.M1();//打印子类的静态字段
        initialization.M2();//使用数组的方式创建
        initialization.M3();//打印一个常量
        initialization.M4();//如果使用常量去引用另外一个常量
    }
    public void M1(){
        System.out.println(SubClaszz.value);
    }
    public void M2(){
        SuperClazz[]sca = new SuperClazz[10];
    }
    public void M3(){
        System.out.println(SuperClazz.HELLOWORLD);
    }
    public void M4(){
        System.out.println(SuperClazz.WHAT);
    }
}

1、调用M1方法

运行结果 对应6 种情况必须立即对类进行“初始化”中的a c
在这里插入图片描述
结果显示:父类子类被加载,但只有父类被初始化(static运行),子类并未被初始化(static未运行)

2、调用M2方法

运行结果
在这里插入图片描述
在这里插入图片描述

结果显示:使用数组的方式, 不会触发初始化(触发父类加载,不会触发子类加载)

3、调用M3

运行结果
在这里插入图片描述

结果显示:打印一个final修饰的常量,不会触发初始化(同样不会触类加载、编译的时候这个常量已经进入了自己class的常量池)

4、调用M4

运行结果
在这里插入图片描述
在这里插入图片描述

结果显示:如果使用常量去引用另外一个不加final修饰的常量,会导致类的初始化

标签:初始化,Java,字节,验证,static,public,加载
From: https://blog.csdn.net/Qvv1koa/article/details/143874523

相关文章

  • 【java开发】Java随机数的种子
    在许多领域,比如模拟、游戏和密码学中,随机数担任非常重要的角色。然而,在计算机领域,随机数并非完全随机,它们是由模拟随机性的算法(称为伪随机性)生成的。在Java中,随机种子就是初始化伪随机数生成器(PRNG,PseudoRandomNumberGenerator)的值。我们一起探讨下,Java中随机种子的工作原理......
  • Java与大数据:二本硕士的最佳职业发展路径
    在当前激烈的就业环境下,二本院校的硕士生常常会陷入迷茫-是专注Java开发,还是投身大数据领域?经过多年的行业观察和实践,我想分享一个明确的答案:以Java为根基,再拓展大数据技术,这是一条稳健且高效的发展路径。作为亲历者和观察者,我看到太多求职者在技术选择上走了弯路。有的同学......
  • 调整方法和相关的注册表项,能帮助你加速 MS Edge 的加载:增强 Google Chrome 浏览器在视
    在Windows11系统中,通过调整MicrosoftEdge浏览器的注册表设置,你可以对其性能进行优化,尤其是提高启动速度和加载速度。以下是一些常见的调整方法和相关的注册表项,能帮助你加速MSEdge的加载:1. 禁用硬件加速硬件加速可能会影响性能,尤其是在资源较少的设备上。如果你遇到性......
  • Javaweb核⼼之转发-重定向
    【⾯面试必备】请求转发RequestDispatcher你知道多少简介:讲解请求转发RequestDispatcher的知识点什么是请求转发:request.getRequestDispatcher(URL地址).forward(request,response)客户端发送请求,Servlet做出业务逻辑处理理。Servlet调⽤用forword()⽅方法,服务器器Servlet把⽬标......
  • [Java] 浮点数的精度丢失问题与精度控制方法
    1需求描述场景1:两个整型相除,如何保证运算结果为浮点数?如何控制运算结果的精度(小数位数)?场景2:针对一个浮点数,如何控制其精度(小数位数)?2试验场景:两整型数相除,控制运算结果、浮点数的精度Longnumber1=110600L;intnumber2=999;intscale=2;//精度n(保留n位小数)/......
  • 记录个Java/Groovy的小问题:空字符串调用split函数返回非空数组
    问题复现最近写了一个groovy替换程序增量流水线脚本(会Java也能看懂),示意脚本如下://获取文件列表方法deflistFiles(folder){defoutput=sh(script:"ls${folder}",returnStdout:true).trim()returnoutput.split('\n')asList}//调用以上方法获取lib目录下......
  • JAVA反序列化学习-CommonsCollections3(基于ysoserial)
    环境准备JDK1.7(7u80)、commons-collections(3.x4.x均可这里使用3.2版本)JDK:https://repo.huaweicloud.com/java/jdk/7u80-b15/jdk-7u80-windows-x64.exe<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</a......
  • 《探索 Java 代码的魅力》
    在编程的世界里,Java无疑是一颗璀璨的明星。它以其强大的功能、跨平台性和广泛的应用场景,成为了众多开发者的首选语言。一、Java的历史与发展Java诞生于1995年,由SunMicrosystems公司推出。它的设计初衷是为了开发一种可以在各种不同的设备上运行的编程语言,以实现“......
  • 《深入理解 Java 类》
    在Java编程中,类(Class)是构建程序的基本单元。它封装了数据和操作这些数据的方法,为代码的组织和复用提供了强大的机制。一、Java类的定义一个Java类通常由以下几个部分组成:类声明:使用关键字“class”来声明一个类,后面跟着类名。例如:classMyClass{}。成员变量:也称......
  • Java 框架:强大的开发利器
    在当今的软件开发领域,Java一直以其强大的性能、跨平台性和丰富的生态系统而备受青睐。而Java框架更是在开发过程中发挥着至关重要的作用,它们为开发者提供了高效、可维护和可扩展的开发方式。一、什么是Java框架?Java框架是一种预先编写好的代码库和工具集合,旨在帮助......