首页 > 编程语言 >【java编程】深入浅出JVM(四):类文件结构

【java编程】深入浅出JVM(四):类文件结构

时间:2024-11-08 11:42:15浏览次数:1  
标签:Java 字节 虚拟机 深入浅出 JVM java 属性 Class 常量

原创 菜菜的后端私房菜

Java文件编译成字节码文件后,通过类加载机制到Java虚拟机中,Java虚拟机能够执行所有符合要求的字节码,因此无论什么语言,只要能够编译成符合要求的字节码文件就能够被Java虚拟机执行.

Java虚拟机和字节码是语言、平台无关性的基石.

本篇文章将深入浅出的解析字节码文件.

一、无关性的基石

曾经: 源代码⏩经过编译⏩本地机器码

Java: 源代码⏩经过编译⏩字节码 ⏩解释器 ⏩ 本地机器码

字节码: 与操作系统和机器指令集无关的,平台中立的程序编译后的存储格式

字节码是无关性的基石。

平台无关性的基石:

所有平台都统一支持字节码
不同的Java虚拟机都可以执行平台无关的字节码

因此实现了 一次编译,到处运行

语言无关性的基石:

Java虚拟机
字节码

Java虚拟机不是只可以执行Java源代码编译而成的字节码,只要符合要求(安全...)的字节码,它都可以执行

因此Kotlin...等语言可以运行在Java虚拟机上

二、Class类文件结构

文件格式存取数据的类型

1、无符号数 : u1,u2,u4,u8代表1,2,4,8个字节的无符号数(可以表示数字,UTF-8的字符串,索引引用....)
2、表: 由n个无符号数或n个表组成(命名以_info结尾)

2.1 初识Class文件格式

2.1.1 编写Java源代码

 public class Test {
     private int m;
     private final int CONSTANT=111;
 
     public int inc() throws Exception {
         int x;
         try {
             x = 1;
             return x;
         }catch (Exception e){
             x = 2;
             return  x;
         }finally{
             x = 3;
         }
     }
 }

2.1.2 使用可视化工具classpy查看反编译的结果

每个集合前都有一个计数器来统计集合中元素的数量

2.1.3 Class文件格式的描述


魔数与主次版本号

魔数: 确定这个文件是否为一个能被虚拟机接受的有效Class文件

主次版本号: 虚拟机拒绝执行超过其版本号的Class文件

    不同版本的Java前端编译器编译生成对应的Class文件主次版本号不同
    支持高版本JVM执行低版本前端编译器生成的Class文件(向下兼容)
    拒绝低版本JVM执行高版本前端编译器生成的Clsss文件

常量池

常量池包含两大常量: 字面量和符号引用

    符号引用
        使用一组符号描述引用(为了定位到目标引用)
        与虚拟机内存布局无关
        还是符号引用时目标引用不一定被加载到内存

    直接引用
        直接执行目标的指针,相对偏移量或间接定位目标引用的句柄
        与虚拟机内存布局相关
        解析直接引用时目标引用已经被加载到内存中

     字面量
         文本字符串
         被final声明的常量

     符号引用
         全限定名
         方法或字段的简单名称和描述符

图中的常量有我们代码中熟悉的常量也有很多没有显示出现在代码中的常量

访问标志:用于识别类或接口的访问信息

是否是一个接口,枚举,模块,注解...

是否被final(public,abstract...)修饰

ACC_PUBLIC:被public修饰

ACC_SUPER: 允许使用invokespecial字节码指令

类索引,父类索引与接口索引集合

类索引指向常量池中表示该类的符号引用

父类索引指向常量池中表示该类父类的符号引用

除了Object外,所有类的父类索引都不为0

我们的例子中没有实现接口,就没有(接口索引集合计数器为0)

字段表集合:描述类声明的字段

字段包括类变量和成员变量(实例变量),不包括局部变量

    简单名称

        字段: 没有描述字段类型的名称
        方法: 没有描述参数列表和返回类型的名称

    描述符

        参数列表按照从左到右的顺序写在()中。

        返回类型写到最后。比如String method(long[],int,String[]) => ([JIL[java.lang.String)Ljava.lang.String

        在前面先写n个[ 再写标识字符。比如java.lang.Integer[ ] => [Ljava.lang.Integer

        字段: 描述字段的类型

        方法: 描述参数列表和返回值

        描述符字符含义(long,boolean,对象类型是J,Z,L 其他都是首字母大写)



         描述符描述n维数组

         描述符描述方法

因此Class文件中字段描述符指向常量池中的#07 I 符号引用(的索引)


    1、字段表集合不会列出父类或父接口中声明的字段

    2、只用 简单名称 来确定字段,所以不能有重名字段

    3、用 简单名称 和 描述符 确定方法,所以方法可以重名(重载)

        字节码文件 规定 简单名称+描述符相同才是同一个方法
        但是 Java语法 规定 重载 = 简单名称相同 + 描述符的参数列表不同 + 描述符的返回类型不能不同

方法表集合:描述类声明的方法

与字段表集合类似

属性表集合:用于描述某些场景专有信息

属性比较多,这里只说明我们例子中出现的,其他的会总结

刚刚在字段,方法表集合中都可以看到属性表集合,说明属性表集合是可以被携带的

Code属性

Java源代码中方法体中的代码经过编译后编程字节码指令存储在Code属性内

其中的异常表集合代表 编译器为这段代码生成的多条异常记录,对应着可能出现的代码执行路径

(程序在try中不抛出异常会怎么执行,抛出异常又会怎么执行....)

Exceptions属性

列举出方法中可能抛出的检查异常(Checked Exception),也就是方法声明throws关键字后面的列举异常

LineNumberTable属性

描述Java源码行号与字节码指令行号(字节码偏移量)对应关系

SourceFile属性

记录生成此Class文件的源码名称

StackMapTable属性

虚拟机类加载验证阶段的字节码验证时,不需要再检验了,只需要查看StackMapTable属性中的记录是否合法

编译阶段将一系列的验证类型结果记录在StackMapTable属性中

ConstantValue:在类加载的准备阶段,为静态变量(常量)赋值

只有类变量才有这个属性

实例变量的赋值: 在实例构造器

类变量的赋值: 在类构造器或 带有ConstantValue属性在类加载的准备阶段

如果类变量被final修饰(此时该变量是一个常量),且该变量数据类型是基本类型或字符串,就会生成ConstantValue属性,该属性指向常量池中要赋值的常量,在类加载的准备阶段,直接把在常量池中ConstantValue指向的常量赋值给该变量

总结所有属性


三、javap解析Class文件

关于javac

javac xx.java :编译Java源文件,不会生成对应的局部变量表

javac -g xx.java :编译Java源文件,生成对应的局部变量表

idea中编译Java源文件使用的是javac -g

关于javap

常用

javap -v 基本上可以反汇编出Class文件中的很多信息(常量池,字段集合,方法集合...)

但是它不会显示私有字段或方法的信息,所以可以使用javap -v -p

详解javap -v -p

public class JavapTest {
     private int a = 1;
     float b = 2.1F;
     protected double c = 3.5;
     public  int d = 10;
 
     private void test(int i){
         i+=1;
         System.out.println(i);
     }
 
     public void test1(){
         String s = "test1";
         System.out.println(s);
     }
 }

标签:Java,字节,虚拟机,深入浅出,JVM,java,属性,Class,常量
From: https://www.cnblogs.com/o-O-oO/p/18534247

相关文章

  • 11.8 javaweb学习 day1 入门
    网页响应流程浏览器前端服务器后端服务器数据库1.浏览器请求前端2.前端响应浏览器3.浏览器请求后端4.后端请求数据库5.数据库响应后端6.后端响应浏览器网页的组成1.网页的文字,图片,音频,视频,超链接什么的,本质是前端代码2.前端代码通过浏览器的转化......
  • 深入探索 Java 8 Stream 流:高效操作与应用场景
    深入探索Java8Stream流:高效操作与应用场景随着Java8的发布,Stream流式处理成为了Java开发中处理集合数据的强大工具。它提供了一种简洁、声明式的方式来操作数据集合,极大地提高了代码的可读性和灵活性。本文将深入探讨Stream流的基本概念、核心操作、常见应用场......
  • Java实现身份证OCR识别API
    近年来,随着业务量的不断增加,人工录入方式越来越难以满足高效办理业务的需求,而且越来越多的移动APP涉及到个人身份证信息的实名认证,为了提高在移动终端上输入身份证信息的速度和准确性,一种可以识别并提取身份证上文字信息的技术接口应运而生,即身份证OCR识别API接口。以下是一......
  • JavaScript中的解构赋值
    写在前面在JavaScript中,解构赋值是一种简洁而强大的语法特性,它允许我们从数组或对象中提取值并将其分配给变量。这个功能可以大大简化代码,提高可读性和可维护性。今天,我们将深入探讨解构赋值的用法和规则。数组解构赋值数组解构赋值允许我们从数组中提取值并将其分配给变......
  • (附项目源码)Java开发语言,基于Java的高校实验室教学管理系统的设计与开发 50,计算机毕设
    摘 要随着高校实验室教学与管理的复杂性增加,传统的手动管理系统已经无法满足日益增长的需求。实验室教学不仅涉及到学生的教学安排和管理,还需要对实验设备、实验材料、实验室资源等进行有效的调配和管理。而目前实验室教学管理的各项工作,如实验室的预约,设备的借用归还、课......
  • (附项目源码)Java开发语言,基于HTML5的智慧养老服务平台的设计与实现 46,计算机毕设程序开
    摘 要随着社会老龄化程度的不断加深,智慧养老发展成为当今社会关注的焦点之一。家庭与社区资源的有限性,使得需要提供更加便捷、贴心的养老服务来满足老年人的需求。基于HTML5技术的智慧养老服务平台的设计和实现,为老年人提供了一个全新的智慧养老服务方式,便于家属和管理员......
  • java项目如何与钉钉机器人对接
    Java项目与钉钉机器人对接,通常涉及创建钉钉群、添加自定义机器人、配置安全设置、以及通过Java代码发送HTTP请求与钉钉机器人进行交互。以下是一个详细的对接流程:一、创建钉钉群并添加自定义机器人创建钉钉群:登录钉钉账号,创建一个新的群聊,或者选择一个已有的群聊。添加自......
  • 移动Web前端高效开发实战:HTML 5 + CSS 3 + JavaScript + Webpack + React Native + Vu
    书:pan.baidu.com/s/1tIHXj9HmIYojAHqje09DTA?pwd=jqsoHTML5新特性与应用:介绍HTML5的新特性,包括语义化标签、本地存储、设备兼容、连接特性等,并讲解如何在移动Web前端开发中充分利用这些特性提升用户体验。CSS3样式与动画设计:详细讲解CSS3的样式设计和动画效果,包括选择器、盒......
  • 宝贝?你居然不知道Javabase有哪些知识,我这有一份为各位准备的《葵花宝典》哟!
    复习大纲文章目录复习大纲变量与类型运算符与输入器条件结构与随机数循环控制结构数组与集合循环嵌套变量与类型基本数据类型:Java中有多种基本数据类型,每种类型都有固定的内存大小和取值范围。整型byte:范围是从-128到127。short:范围是从-32768到32767。int......
  • 书接上回说一说 JVM 中的方法区和直接内存
    方法区:在《Java虚拟机规范》中明确说明:尽管所有的方法区在逻辑上是堆内存的一部分,但一些简单的实现可能不会选择对方法区进行垃圾回收或者进行压缩。但对于HotSpot虚拟机来说,方法区还有一个名字叫Non-Heap(非堆)目的就是要和方法区分开。所以,这样来看,方法区是一块独立于......