首页 > 编程语言 >Java字节码文件详解​

Java字节码文件详解​

时间:2024-01-09 21:33:21浏览次数:36  
标签:文件 Java 字节 版本号 局部变量 指令 public 详解

03.字节码文件详解

JVM的组成

从字节码文件的执行流程看JVM的组成:

1.准备好字节码文件(自己编译或其他人传给你)

2.使用类加载器ClassLoader加载(此时JVM已参与)

3.运行时数据(JVM管理的内存)

4.执行引擎(即时编译器、解释器垃圾回收器等):将字节码文件中的指令解释成机器码,同时使用即时编译器优化性能

Java字节码文件详解​_局部变量



字节码文件组成

以正确的姿势打开文件

字节码文件中保存了源代码编译之后的内容,以二进制的方式存储,无法直接用记事本打开阅读。

例如通过NotePad++使用十六进制插件查看class文件:

Java字节码文件详解​_局部变量_02


不直观。

因此,推荐使用jclasslib工具查看字节码文件。

Github地址:https://github.com/ingokegel/jclasslib

Java字节码文件详解​_局部变量_03



Class字节码文件的内容

Java字节码文件详解​_版本号_04


  • 基础信息魔数、字节码文件对应的Java版本号访问标识(public final等等)父类和接口
  • 常量池保存了字符串常量、类或接口名、字段名主要在字节码指令中使用
  • 字段当前类或接口声明的字段信息
  • 方法当前类或接口声明的方法信息字节码指令
  • 属性类的属性,比如源码的文件名内部类的列表等


字节码文件的基本信息

字节码文件的组成部分-Magic魔数

●文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改,不影响文件的内容。

●软件使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错。

Java字节码文件详解​_局部变量_05



字节码文件的组成部分-主副版本号

主副版本号指的是编译字节码文件的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号。

Java字节码文件详解​_字节码_06


1.2之后大版本号计算方法就是:

主版本号-44

比如主版本号52就是JDK8


主版本号不兼容导致的错误

需求:

解决以下由于主版本号不兼容导致的错误

类文件具有错误的版本52.0,应为50.0请删除该文件或确保该文件位于正确的类路径子目录中。

解决方法:

两种方案:

1.升级JDK版本(容易引发其他的兼容性问题,并且需要大量的测试)

2.将第三方依赖的版本号降低或者更换依赖,以满足JDK版本的要求

一般选择第二种方法解决。

升级JDK版本:

Java字节码文件详解​_局部变量_07



Java字节码文件详解​_局部变量_08



Java字节码文件详解​_局部变量_09



降低依赖的版本:

Java字节码文件详解​_版本号_10



小结

Java字节码文件详解​_字节码_11



字节码文件的常量池和方法

常量池

字节码文件中常量池的作用:避免相同的内容重复定义,节省空间。常量池中的数据都有一个编号,编号从1开始。在字段或者字节码指令中通过编号可以快速的找到对应的数据。字节码指令中通过编号引用到常量池的过程称之为符号引用

Java字节码文件详解​_局部变量_12



方法

字节码中的方法区域是存放字节码指令的核心位置,字节码指令的内容存放在方法的Code属性中。

源代码:

public class Demo1 {
 public static void main(String[] args) {
 int i = 0;
 i = i++;
 System.out.println(i);
 }
}


Java字节码文件详解​_字节码_13



标准答案:答案是0,我通过分析字节码指令发现,i++先把0取出来放入临时的操作数栈中,接下来对i进行加1,i变成了1,最后再将之前保存的临时值0放入i,最后i就变成了0。

如果改成i = ++i;则最后结果为1,他们的字节码指令顺序有了掉换。


常用指令学习

示例代码:

public class Demo2 {
 public static void main(String[] args) {
 int i = 0;
 int j = i + 1;
 }
}

对应的字节码指令:

Java字节码文件详解​_版本号_14


在程序执行时有操作数栈(临时存放)和局部变量表数组(局部变量存放位置),如下图:

Java字节码文件详解​_版本号_15


  • iconst_x指令,将常量x存入操作数栈
  • istore_x指令,将操作数栈最上面的数存入编号为x的局部变量表数组中
  • iload_1指令,将序号为x的局部变量存入操作数栈
  • iinc指令,将局部变量增加常数。该指令的格式一般为:iinc x by i,意为将本地变量表里编号为x的数加上i,并将结果存到原地。这个指令比较特别,它直接将局部变量表中的数值加上指定的值,结果直接保存在局部变量在局部变量表中原来的位置,不通过操作数栈。


练习

查看字节码文件并解答问题。问题:

通过字节码指令分析下面三种“加一”的操作性能的高低?

Java字节码文件详解​_字节码_16


一般来说,字节码指令越多则相应的性能就会越低。

Java代码:

public class Test1 {
 public static void main(String[] args) {
 int i = 0, j = 0, k = 0;
 i++;
 j = j + 1;
 k += 1;

 System.out.printf("i=%d j=%d k=%d",i,j,k);
 }
}

编译后class文件的本地变量表(Loacl Variable Table):

Java字节码文件详解​_字节码_17


指令列表:

Java字节码文件详解​_版本号_18


(指令列表不包含最后的输入语句部分)

i++操作:第7行

j = j + 1操作:第8行 到 第11行

k += 1操作:第12行

因此,i++操作与k += 1的效率相当,优于j = j + 1操作。






标签:文件,Java,字节,版本号,局部变量,指令,public,详解
From: https://blog.51cto.com/tangxiaohu/9166051

相关文章

  • JPEG格式详解Baseline、Progressive的区别
    JPEG的简介JPEG(JointPhotographicExpertsGroup)是一种常见的图像压缩格式,它采用有损压缩方法以减小文件大小。在保存JPEG格式的图片时,有一些常见的选项和参数,它们可以影响图像的质量和文件大小。以下是一些常见的保存方式及其区别:压缩质量/压缩比率质量:JPEG图像可以以不同的......
  • 通过印模生成电子印章-Java源代码
    以下代码是处理印模图片的核心代码,通过以下代码可以将公章图片转换为电子印章图片。制作方式分为四步:1、在白纸上加盖印章;2、把加盖印章的白纸扫描,形成图片;3、将图片通过下面的代码进行自动透明化抠图处理;4、程序返回自动透明化抠图处理后的电子印章图片。5、处理后的电子印章效果(......
  • java生成企业公章图片源代码
    企业公章图片在电子签章业务中应用广泛,在电子签章应用过程中首先需要生成公章图片,然后再使用公章图片结合数字签名技术完成电子签,这样就实现了从可视化到不可篡改的数字化电子签章功能,以下是企业公章图片生成源代码。importcom.resrun.utils.Base64;importorg.apache.pdfbox.io.......
  • java的idea使用maven下载依赖速度过慢解决
    idea页面双击shift键,搜索settings.xml然后将以下代码复制到xml中间的settings中间切换为阿里源<mirrors><!--mirror|Specifiesarepositorymirrorsitetouseinsteadofagivenrepository.Therepositorythat|thismirrorserveshasanIDthatmatc......
  • java8日期时间格式化DateTimeFormatter多个格式
    原文地址:datetimeformatter.ofpatternmultipleformats-掘金DateTimeFormatter 是一个用于日期时间格式化和解析的类。使用 ofPattern 方法可以创建一个格式化器,该方法接受一个日期时间格式的字符串作为参数。如果您需要在同一个 DateTimeFormatter 对象中支持多种不同的......
  • Linux下PCI设备驱动开发详解(八)
    Linux下PCI设备驱动开发详解(八)RIFFA的Linux驱动文件夹下有6个C源码文件,riffa_driver.c、riffa_driver.h、circ_queue.c、circ_queue.h、riffa.c、riffa.h。其中riffa.c和riffa.h不属于驱动源码,它们是系统函数调用驱动封装的一层接口,属于用户态应用程序的一部分。在讲解riffa之前,我......
  • Java多线程编程中的异常处理策略
    第1章:引言大家好,我是小黑,咱们今天聊聊异常处理。想必大家在写代码的时候都遇到过各种各样的异常吧?有时候,一个小小的异常如果处理不当,就可能导致整个程序崩溃。特别是在多线程环境下,异常处理就像是在拆雷,稍不留神,程序就可能“炸”了。为啥多线程编程中的异常处理这么重要呢?咱们......
  • JavaScript apply、call、bind 函数详解
    apply和callapply和call非常类似,都是用于改变函数中this的指向,只是传入的参数不同,等于间接调用一个函数,也等于将这个函数绑定到一个指定的对象上:letname='window'functiongetName(param1,param2){console.log(this.name)console.log(param1,param2)}letobj=......
  • Java学习建议
    很多大学生、在职员工、IT爱好者都会选择学习Java来提升自己的专业技能,那么在学习之前做好充分的准备也是必须的。建议大家不妨仔细研究下如何快速系统入门,这样才利于更好的掌握Java技术。以下是对于Java学习的一些建议,供参考。 1.了解Java,明确自己的学习目标 Java是一门面向对......
  • 基于Java的在线教育平台设计与实现
    一、 选题依据及意义随着电子技术和网络信息的迅速发展,互联网正在政治、经济、文化各个领域引发着一场影响广泛而深远的革命。利用互联网展开的网上教育,已经越来越成为衡量一个地方教育综合发展的重要指标之一。21世纪是一个网络平台的信息时代,随着网络应用的普及和深入,目前网络......