热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

类的加载过程详解

在java中数据类型分为基本数据类型和引用数据类型。基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载。按照java虚拟机规范,从class

在java中数据类型分为基本数据类型和引用数据类型。基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载。

按照java虚拟机规范,从class文件到加载进入内存中的类,再到类卸载出内存为止,整个生命周期如下


一、加载

将java类的字节码文件加载到机器内存中,并在内存中构建出java类的原型(类模板对象)


1、加载类时,java虚拟机加载步骤

(1)通过类的全名,获取类的二进制数据流

(2)解析类的二进制数据流为方法区内的数据结构(Java类模型)

(3)创建java.lang.Class类的实例,作为方法区这个类的各种数据的访问入口


2、类模型和Class实例的位置

(1)类模型存储在方法区

(2)class文件加载到元空间后,会在堆中创建一个Class对象,用来封装类位于方法区内的数据结构。每一个类都对应一个Class对象

Class类的构造方法是私有的,只有jvm可以创建。


3、数组类的加载

数组类本身并不是由类加载器负责创建,而是由jvm在运行时根据需要直接创建的,但是数组的元素类型仍然需要依靠类加载器去创建。创建步骤如下

(1)如果数组的元素类型是引用类型,那么遵循定义的加载过程递归加载和创建数组A的元素类型

(2)jvm使用指定的元素类型和数组维度类创建新的数组类。


二、链接


1、验证

保证加载的字节码是合法的。

验证通过之后类加载器才会将类的二进制数据加载到方法区中,除格式验证之外的验证操作是在方法区中进行

(1)格式验证

是否以魔数0xCAFEBABE开头,主版本和副版本是否在当前的java虚拟机的支持范围内等。

(2)语义检查

是否所有的类都存在父类(在java里,除了Object之外,其他类都有父类)

是否一些被定义为final的方法或者类被重写或者继承了

非抽象类是否实现了所有抽象方法或者接口方法

是否存在不兼容的方法

(3)字节码验证

在字节码执行的过程中,是否会跳转到一条不存在的指令(不能达到100%验证)

函数的调用是否传递了正确类型的参数

变量的赋值是不是给了正确的数据类型等

注:

栈映射帧(StackMapTable)是处于该阶段,在检测特定的字节码时,其局部变量表和操作数栈是否有着正确的数据类型。

(4)符号引用验证

Class文件在常量池会通过字符串记录自己将要使用的其他类或者方法。在验证阶段,虚拟机会检查类或者方法是否存在,访问权限是否受限等。如果一个类在系统中找不到,则抛出NoClassDefFoundError,如果一个方法无法找到,则抛出NoSuchMethodError。


2、准备

当一个类通过验证,就会进入准备阶段,为静态变量分配内存,并初始化默认值。

java不支持boolean类型,内部实现是int,由于int默认值为0,所以boolean的默认值为false.


3、解析

将接口,字段和方法的符号引用转换为直接引用。

java虚拟机为每一个类都准备一张方法表,将其所有的方法列在其中,当需要调用一个类的方法时,只要知道这个方法在方法表的偏移量(通过解析操作,符号引用转换为直接引用类中的方法表中的位置),就可以直接调用该方法了。

不过java虚拟机规范并没有明确要求解析阶段一定要按序执行,在hotspot中,按照加载,验证,准备和初始化的顺序执行,但链接阶段的解析操作往往伴随着jvm执行完初始化之后再执行。


三、初始化

类的初始化时类装载的最后一个阶段,也是真正开始执行类定义的java的程序代码()方法

在加载一个类之前会先加载其父类,因此父类的方法总是在子类方法之前被调用。


1、使用static+final修饰,且显示赋值中不涉及到方法或者构造器调用的基本数据类型或者String类型的显示赋值,是在链接阶段的准备环节进行赋值。

public static int a = 1;//在初始化阶段()中赋值
public static final int INT_CONSTANT = 10;//在链接阶段的准备环节赋值public static final Integer INTEGER_CONSTANT1 = Integer.valueOf(100);//在初始化阶段()中赋值
public static Integer INTEGER_CONSTANT2 = Integer.valueOf(1000);//在初始化阶段()中赋值public static final String s0 = "helloworld0";//在链接阶段的准备环节赋值
public static final String s1 = new String("helloworld1");//在初始化阶段()中赋值public static String s2 = "helloworld2";public static final int NUM1 = new Random().nextInt(10);//在初始化阶段()中赋值

2、线程安全性

虚拟机会保证一个类的()方法在多线程环境中被正确的加锁,同步。

class StaticA {static {try {Thread.sleep(1000);} catch (InterruptedException e) {}try {Class.forName("com.atguigu.java1.StaticB");} catch (ClassNotFoundException e) {e.printStackTrace();}System.out.println("StaticA init OK");}
}
class StaticB {static {try {Thread.sleep(1000);} catch (InterruptedException e) {}try {Class.forName("com.atguigu.java1.StaticA");} catch (ClassNotFoundException e) {e.printStackTrace();}System.out.println("StaticB init OK");}
}public class StaticDeadLockMain extends Thread {private char flag;public StaticDeadLockMain(char flag) {this.flag = flag;this.setName("Thread" + flag);}@Overridepublic void run() {try {Class.forName("com.atguigu.java1.Static" + flag);} catch (ClassNotFoundException e) {e.printStackTrace();}System.out.println(getName() + " over");}public static void main(String[] args) throws InterruptedException {StaticDeadLockMain loadA = new StaticDeadLockMain('A');loadA.start();StaticDeadLockMain loadB = new StaticDeadLockMain('B');loadB.start();}
}


推荐阅读
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文详细解析了Java类加载系统的父子委托机制。在Java程序中,.java源代码文件编译后会生成对应的.class字节码文件,这些字节码文件需要通过类加载器(ClassLoader)进行加载。ClassLoader采用双亲委派模型,确保类的加载过程既高效又安全,避免了类的重复加载和潜在的安全风险。该机制在Java虚拟机中扮演着至关重要的角色,确保了类加载的一致性和可靠性。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 出库管理 | 零件设计中的状态模式学习心得与应用分析
    出库管理 | 零件设计中的状态模式学习心得与应用分析 ... [详细]
  • 深入理解Java中的多态性概念及其应用
    多态是面向对象编程中的三大核心特性之一,与封装和继承共同构成了面向对象的基础。多态使得代码更加灵活和可扩展,封装和继承则为其提供了必要的支持。本文将深入探讨多态的概念及其在Java中的具体应用,帮助读者全面理解和掌握这一关键知识点。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 本文提出了一种基于栈结构的高效四则运算表达式求值方法。该方法能够处理包含加、减、乘、除运算符以及十进制整数和小括号的算术表达式。通过定义和实现栈的基本操作,如入栈、出栈和判空等,算法能够准确地解析并计算输入的表达式,最终输出其计算结果。此方法不仅提高了计算效率,还增强了对复杂表达式的处理能力。 ... [详细]
author-avatar
君慎豫行
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有