首页 > 编程语言 >深入理解Java虚拟机

深入理解Java虚拟机

时间:2024-06-18 20:22:11浏览次数:25  
标签:初始化 Java 字节 静态 虚拟机 深入 引用 赋值 加载

类加载

加载

java数据类型分为基本数据类型和引用数据类型,
基本数据类型由虚拟机预先定义,引用数据类型才需要类的加载过程。

类的加载,就是将java类的字节码文件加载到内存中,并通过字节码在内存中构建出类的原型---类模板对象。
jvm把字节码中的常量池,类字段,类方法等信息存储到类模板中,这样jvm在运行期间才能获得类的全部信息。
反射也基于这一基础。

加载阶段主要做的事情:

首先通过类的全类名(包名加类名)找到类的字节码文件,有下面几种方法读入字节码

  • 可以通过文件系统读入后缀为.class的文件
  • 可以通过读入jar,zip包,提取字节码
  • 可以读取数据库中的字节码
  • 可以使用http协议传输字节码
  • 可以使用运行时生成的字节码

解析字节码文件,生成内存中的该类的数据结构,也就是类的模板,如果这个字节码不符合规范会抛出classformaterror错误
类的模板存放在方法区中,方法区在元空间(使用本地内存)中

在堆中创建java.lang.class类的实例,指向上一步生成的类的模板,外部就通过堆中的这个实例来访问类中的各种信息。
java.lang.class的构造方法是私有的,只有jvm可以创建。

PS:数组类的加载有些特殊,数组类本身并不是由类加载器负责的,而是jvm在运行时根据需要直接创建的,但数组的元素类型仍然需要类加载器创建,

链接

验证:保证加载的字节码是规范的
格式检查:格式检查和字节码的加载一起执行,格式检查通过后,类加载器才会把类的字节码加载到方法区中。
(格式检查之外的检查会在类的字节码加载到方法区之后执行)
(格式检查举例包括,魔数检查,版本检查等)
语义检查
字节码验证
符号引用验证

准备:准备阶段就是为类的静态变量分配内存,并将其设置为默认值,并不是代码里的默认值,而是jvm给这些变量的默认值。
如果静态变量是static final修饰的基本数据类型,直接赋值常量,在准备阶段显式赋值,也就是赋予代码中的指定值。
而如果是static final修饰的String,使用字面量赋值,在准备阶段显式赋值,也就是赋予代码中的指定值。
注意这里只是静态变量,类的静态变量和类模板一起放在方法区,而类的实例变量则分配在堆中。

解析:将类,接口,字段,方法的符号引用转换为直接引用
符号引用(Symbolic Reference): 符号引用是一种用符号来表示引用目标的引用形式。在符号引用阶段,引用的目标并没有直接指定目标的内存地址,而是以符号的形式表示。符号引用可以是类名、字段名、方法名等,它们是一种抽象的引用。

直接引用(Direct Reference): 直接引用是指可以直接定位目标的引用形式。与符号引用不同,直接引用包含了目标的直接内存地址或偏移量,可以直接定位到目标。
方法区中本来存储的都是一些符号,比如我使用了某个类的某个方法,但是只存了类和方法的名字,仅有这些信息是没有办法执行的,还要把这些符号转成真正的地址。

PS:当java代码中直接使用字符串常量时,就会在常量池中生成constant_string,他表示字符串常量,并会引用constant_utf8的常量项,在常量池中会维护字符串常量池,保存所有出现过的字符串常量并且没有重复项。

初始化

初始化阶段,为类的静态变量赋值和执行静态代码块的过程,
类的初始化阶段才会执行java字节码,也就是java程序中的代码
类的初始化阶段最重要的工作是执行类的初始化方法()
该方法由编译器生成,jvm执行,程序员是无法调用的,也不能定义一个同名的方法。
这个方法的主要内容就是类的静态变量的赋值语句和静态代码块
另外,在尝试初始化一个类的时候,jvm总是会试图先加载该类的父类,
因此父类的()函数总是在子类的()函数之前调用,也就是说父类的static静态代码块优先于子类的静态代码块。

下面有一些特殊情况,有些类的字节码文件中不会产生()函数,
如果类中没有静态变量和静态代码块,自然就不会有()函数
如果类中有静态变量但是没有静态变量的赋值语句,也没有静态代码块,自然就不会有()函数

注意:以上可以看到有静态变量的赋值就会有clinit函数,但是有一些特殊情况,即使有静态变量的赋值也不会产生clinit函数,这是因为这些显式赋值在链接的准备阶段就做了。
如果静态变量是static final修饰的基本数据类型,并且直接赋值常量,那么在准备阶段就已经被显式赋值了,不会生成()函数
而如果是static final修饰的String,使用字面量赋值,那么在准备阶段就已经被显式赋值了,不会生成()函数。

()方法需要线程安全,如果有多个线程想去初始化同一个类也就是执行同一个()方法,那么应该只会有一个线程被允许去执行这个方法,其他线程都要被阻塞。
如果一个线程已经加载了类,那么其他线程都不应该重复加载这个类,当需要再次使用这个类时,虚拟机会直接返回已经准备好的信息。

类的主动使用

只有类的主动使用会调用方法,
主动使用包括,

创建一个类的实例的时候,包括使用new关键字,使用反射,克隆,序列化
调用类的静态方法的时候,
使用类或者接口的静态字段(注意有一些加final的常量在准备阶段就已经产生了,所以不需要调方法),
使用java.lang.reflect包中的方法反射类的方法的时候,比如使用class.forname("")
当初始化子类发现父类还没有进行过初始化,需要先触发其父类的初始化
这条规则对接口并不适用,初始化一个类的时候,并不会初始化它所实现的接口
初始化一个接口的时候,并不会初始化父接口
如果一个接口定义了default方法,那么当初始化直接或间接实现该接口的类时,会先触发接口的初始化。
当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类
当初次调用methodhandle实例时,初始化该Methodhandle指向的方法所在的类。
为什么需要自定义类加载器

首先介绍自定义类的应用场景:
(1)加密:Java代码可以轻易的被反编译,如果你需要把自己的代码进行加密以防止反编译,可以先将编译后的代码用某种加密算法加密,类加密后就不能再用Java的ClassLoader去加载类了,这时就需要自定义ClassLoader在加载类的时候先解密类,然后再加载。
(2)从非标准的来源加载代码:如果你的字节码是放在数据库、甚至是在云端,就可以自定义类加载器,从指定的来源加载类。
(3)以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理。这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出在Java虚拟机中运行的类。

标签:初始化,Java,字节,静态,虚拟机,深入,引用,赋值,加载
From: https://www.cnblogs.com/DCFV/p/18255047

相关文章

  • Java访问控制符及final
    1、访问控制符在Java语言中,访问控制修饰符有4种,分别是public、private、protected和default。1) private用private修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用。因此,private修饰符具有最高的保护级别。2)default(默......
  • Java毕业设计 基于SSM助学贷款管理系统
    Java毕业设计基于SSM助学贷款管理系统SSM助学贷款管理系统功能介绍学生:登录修改密码学生信息贷款项目信息申请贷款留言信息公告学校负责人:登录修改密码学生管理学校负责人信息贷款项目贷款申请审批留言信息公告银行负责人:登录修改密码银行负责人信息......
  • 数组趣味玩法:在Java SE中尝试创新玩法
    哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的......
  • 深入探究:Java SE中的数组高级用法
    哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的......
  • 在现代编程环境中,Perl 如何与其他流行语言(如 Python、Java 等)进行集成和协作?
    在现代编程环境中,Perl可以与其他流行语言(如Python、Java等)进行集成和协作。以下是一些常见的方法:调用外部程序:Perl可以使用系统调用来执行其他语言编写的可执行文件。这意味着可以从Perl中调用Python、Java等程序,并将它们的输出捕获到Perl程序中进行处理。使......
  • 滚雪球学Java(65-3):详解Java IdentityHashMap的内部实现原理
      咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及JavaSE相关知识点了,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~......
  • Java环境搭建
    Java是一门程序编程语言;除了Java编程语言,很多的编程语言:C、前端html/css+js等;python不同编程语言,好比不同国家的语言;不同编程语言的应用场景不同;Java是一门后台的、后端的编程语言一、Java语言的特点:1.简单性:相对c、c++2.开源性:开放源代码 3.编程资源广泛......
  • 闲说: Java 中Comparable 和 Comparator 的区别
    共同点Comparable和Comparator他们都可以实现集合的排序功能;区别Comparable被实现类实现后,需要重写compareTo方法,方可使用Collections/Arrays工具类提供的排序方法进行排序;Comparator被实现类实现后,也可以重写compare方法,这个方法虽然能返回两个对象的大小......
  • 数据结构与算法-红黑树的java实现-构建红黑树
    红黑树红黑树是一种二分查找树,与普通的二分查找树不同的一点是,红黑树的每个节点都有一个颜色(color)属性。该属性的值要么是红色,要么是黑色。通过限制从根到叶子的任何简单路径上的节点颜色,红黑树确保没有比任何其他路径长两倍的路径,从而使树近似平衡。节点红黑树的节......
  • 计算机Java项目|房屋租赁管理系统的设计与实现
    作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互助收藏点赞不迷路 ......