做网站可以卖钱吗/做网页用什么软件好
Java 字节码简介
Java 中的字节码,英文名为
bytecode
, 是 Java 代码编译后的中间代码格式。JVM 需要读取并解析字节码才能执行相应的任务。
从技术人员的角度看,Java 字节码是 JVM 的指令集
。JVM 加载字节码格式的 class 文件,校验之后通过 JIT 编译器转换为本地机器代码执行。 Java 字节码就是 JVM 执行的指令格式。
Java bytecode
由单字节(byte
)的指令组成,理论上最多支持 256
个操作码(opcode)。实际上 Java 只使用了 200 左右的操作码, 还有一些操作码则保留给调试操作。
操作码, 下面称为 指令
, 主要由类型前缀
和操作名称
两部分组成。
例如,’i
’ 前缀代表 ‘integer
’,所以,’iadd
’ 很容易理解, 表示对整数执行加法运算。
根据指令的性质,主要分为四个大类:
- 栈操作指令,包括与局部变量交互的指令
- 程序流程控制指令
- 对象操作指令,包括方法调用指令
- 算术运算以及类型转换指令
此外还有一些执行专门任务的指令,比如同步(synchronization)指令,以及抛出异常相关的指令等等。
获取字节码清单
可以用 javap
工具来获取 class 文件中的指令清单。 javap
是标准 JDK 内置的一款工具, 专门用于反编译 class 文件。
先创建一个简单的类仅创建一个对象,后续慢慢扩充。
package com.lkl.jvmDemo;public class HelloByteCode {public static void main(String[] args) {HelloByteCode obj = new HelloByteCode();}
}
编译这个类:
javac HelloByteCode.java
使用 javac
编译 ,直接在当前目录执行上述指令,得到对应的 class 即可。
javac 不指定
-d
参数编译后生成的.class
文件默认和源代码在同一个目录。注意:
javac
工具默认开启了优化功能, 生成的字节码中没有局部变量表(LocalVariableTable),相当于局部变量名称被擦除。如果需要这些调试信息, 在编译时请加上-g
选项。JDK 自带工具的详细用法, 请使用:
javac -help
或者javap -help
来查看; 其他类似。
使用 javap
工具来执行反编译, 获取字节码清单:
还是在上述目录,执行下面指令:
javap -c HelloByteCode
或者
javap -c HelloByteCode.class
编译结果如下:
Compiled from "HelloByteCode.java"
public class com.lkl.jvmDemo.HelloByteCode {public com.lkl.jvmDemo.HelloByteCode();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: new #7 // class com/lkl/jvmDemo/HelloByteCode3: dup4: invokespecial #9 // Method "<init>":()V7: astore_18: return
}
解读字节码清单
反编译后的代码清单中, 有一个默认的构造函数 public com.lkl.jvmDemo.HelloByteCode()
, 以及 main
方法。
Java基础中,创建一个类如果不定义任何构造函数,就会有一个默认的无参构造函数,这里再次验证了这个知识点。查看编译后的 class 文件证实了其中存在默认构造函数,所以这是 Java 编译器生成的, 而不是运行时JVM自动生成的。
默认构造函数一些指令
回顾 Java 知识, 每个构造函数中都会先调用 super
类的构造函数,但这不是 JVM 自动执行的, 而是由程序指令控制,所以默认构造函数中也就有一些字节码指令来干这个事情。
基本上,这几条指令就是执行 super()
调用:
public com.lkl.jvmDemo.HelloByteCode();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: return
其中解析的 java/lang/Object
不用说, 默认继承了 Object 类。这里再次验证了这个知识点,而且这是在编译期间就确定了的。
main函数指令
public static void main(java.lang.String[]);Code:0: new #7 // class com/lkl/jvmDemo/HelloByteCode3: dup4: invokespecial #9 // Method "<init>":()V7: astore_18: return
main 方法中创建了该类的一个实例, 然后就 return了,关于里面的几个指令, 稍后讲解。
查看 class 文件中的常量池信息
常量池
英文是 Constant pool
。这里做一个强调:大多数时候指的是 运行时常量池
。但运行时常量池里面的常量是从哪里来的呢? 主要就是由 class 文件中的 常量池结构体
组成的。
要查看常量池信息,需要加一点魔法参数:
javap -c -verbose HelloByteCode
在反编译 class 时,指定 -verbose
选项, 则会 输出附加信息
。
Classfile /XXX/com/lkl/jvmDemo/HelloByteCode.classLast modified 2023-10-29; size 304 bytesMD5 checksum 565e4ca34e83f69df37c1f35c971375fCompiled from "HelloByteCode.java"
public class com.lkl.jvmDemo.HelloByteCodeminor version: 0major version: 65flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref #2.#3 // java/lang/Object."<init>":()V#2 = Class #4 // java/lang/Object#3 = NameAndType #5:#6 // "<init>":()V#4 = Utf8 java/lang/Object#5 = Utf8 <init>#6 = Utf8 ()V#7 = Class #8 // com/lkl/jvmDemo/HelloByteCode#8 = Utf8 com/lkl/jvmDemo/HelloByteCode#9 = Methodref #7.#3 // com/lkl/jvmDemo/HelloByteCode."<init>":()V#10 = Utf8 Code#11 = Utf8 LineNumberTable#12 = Utf8 main#13 = Utf8 ([Ljava/lang/String;)V#14 = Utf8 SourceFile#15 = Utf8 HelloByteCode.java
{public com.lkl.jvmDemo.HelloByteCode();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 3: 0public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new #7 // class com/lkl/jvmDemo/HelloByteCode3: dup4: invokespecial #9 // Method "<init>":()V7: astore_18: returnLineNumberTable:line 5: 0line 6: 8
}
显示了很多关于 class 文件信息: 编译时间, MD5 校验和, 从哪个 .java
源文件编译得来,符合哪个版本的 Java 语言规范等等。
还可以看到 ACC_PUBLIC
和 ACC_SUPER
访问标志符。 ACC_PUBLIC
标志很容易理解:这个类是 public
类,因此用这个标志来表示。
但 ACC_SUPER
标志是怎么回事呢? 这就是历史原因, JDK 1.0 的 BUG 修正中引入 ACC_SUPER
标志来修正 invokespecial
指令调用 super 类方法的问题,从 Java 1.1 开始, 编译器一般都会自动生成ACC_SUPER
标志。
摘取一部分内容,可以看到常量池中的常量定义。还可以进行组合,一个常量的定义中可以引用其他常量。
Constant pool:#1 = Methodref #2.#3 // java/lang/Object."<init>":()V#2 = Class #4 // java/lang/Object#3 = NameAndType #5:#6 // "<init>":()V#4 = Utf8 java/lang/Object#5 = Utf8 <init>
第一行: #1 = Methodref #2.#3 // java/lang/Object."<init>":()V
, 解读如下:
#1
常量编号, 该文件中其他地方可以引用。=
等号就是分隔符.Methodref
表明这个常量指向的是一个方法;具体是哪个类的哪个方法呢? 类指向的#2
, 方法签名指向的#3
; 当然双斜线注释后面已经解析出来可读性比较好的说明了。
总结一下,常量池就是一个常量的大字典,使用编号的方式把程序里用到的各类常量统一管理起来,这样在字节码操作里,只需要引用编号即可。
查看方法信息
在 javap
命令中使用 -verbose
选项时, 还显示了其他的一些信息。 例如, 关于 main
方法的更多信息被打印出来:
public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=1
可以看到方法描述: ([Ljava/lang/String;)V
:
- 其中小括号内是入参信息/形参信息;
- 左方括号表述数组;
L
表示对象;- 后面的
java/lang/String
就是类名称; - 小括号后面的
V
则表示这个方法的返回值是void
; - 方法的访问标志也很容易理解
flags: ACC_PUBLIC, ACC_STATIC
,表示 public 和 static。
可以看到执行该方法时需要的栈(stack)深度是多少,需要在局部变量表中保留多少个槽位, 还有方法的参数个数: stack=2, locals=2, args_size=1
。把上面这些整合起来其实就是一个方法:
public static void main(java.lang.String[]);
注:实际上一般把一个方法的修饰符+名称+参数类型清单+返回值类型,合在一起叫
“方法签名”
,即这些信息可以完整的表示一个方法。
编译器自动生成的无参构造函数字节码:
public com.lkl.jvmDemo.HelloByteCode();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=1
会发现一个奇怪的地方, 无参构造函数的参数个数居然不是 0: stack=1, locals=1, args_size=1
。 这是因为在 Java 中, 如果是静态方法则没有 this
引用。 对于非静态方法, this
将被分配到局部变量表的第 0 号槽位中。
线程栈与字节码执行模型
JVM 是一台基于栈的计算机器。每个线程都有一个独属于自己的线程栈(JVM stack),用于存储栈帧
(Frame)。每一次方法调用,JVM都会自动创建一个栈帧。栈帧
由 操作数栈
, 局部变量数组
以及一个class 引用
组成。class 引用
指向当前方法在运行时常量池中对应的 class)。
局部变量数组
就是局部变量表
(LocalVariableTable), 其中包含了方法的参数,以及局部变量。 局部变量数组的大小在编译时就已经确定: 和局部变量+形参的个数有关,还要看每个变量/参数占用多少个字节。操作数栈是一个 LIFO 结构的栈, 用于压入和弹出值。 它的大小也在编译时确定。
相关文章:

Java字节码技术
Java 字节码简介 Java 中的字节码,英文名为 bytecode, 是 Java 代码编译后的中间代码格式。JVM 需要读取并解析字节码才能执行相应的任务。 从技术人员的角度看,Java 字节码是 JVM 的指令集。JVM 加载字节码格式的 class 文件,校验之后通过 J…...

Java SE 学习笔记(十八)—— 注解、动态代理
目录 1 注解1.1 注解概述1.2 自定义注解1.3 元注解1.4 注解解析1.5 注解应用于 junit 框架 2 动态代理2.1 问题引入2.2 动态代理实现 1 注解 1.1 注解概述 Java 注解(Annotation)又称Java标注,是JDK 5.0引入的一种注释机制,Java语…...

虚拟内存之请求分页管理
一、与基本分页存储管理的区别 程序执行过程中,访问信息不在内存时,OS需要从外存调入内存。——>调页功能 内存空间不够时,OS需要将内存中暂时用不到的信息换出到外存。——>页面置换功能 二、页表机制 1.页表:需要知道页面…...

lazarus开发:提升sqlite数据插入速度
目录 1 前言 2 优化数据容器 3 开启事务插入数据 4 其他方面优化 1 前言 近期有一个需求是向数据库中插入excel文件中的10万多条数据,接近70个字段。最初整个插入数据时间是大约40分钟,经过优化调整后,大幅优化为大约5分钟。这里简单介绍…...

瑞萨RH850-P1X ECM和英飞凌TC3xx SMU对比
1.1 基本结构 P1X ECM(Error Control Module)收集从不同的错误源和监控电路发来的错误信号,并通过error pin(ERROROUTZ)对外输出、产生中断并发出ECM reset信号。 P1x-C系列根据产品型号不同,ECM个数也不相同,如下: 对应寄存器基地…...

Ajax学习笔记第三天
做决定之前仔细考虑,一旦作了决定就要勇往直前、坚持到底! 【1 ikunGG邮箱注册】 整个流程展示: 1.文件目录 2.页面效果展示及代码 mysql数据库中的初始表 2.1 主页 09.html:里面代码部分解释 display: inline-block; 让块元素h1变成行内…...

ESP32-C3 低功耗懒人开关:传统开关轻松上云和本地控制
项目背景 随着科技的快速发展,智能家居已经成为我们日常生活的一部分。而对于基础设施已经配备完毕的家庭而言,对家居设备的智能化改造是一项相对困难的工作。本文将分享一款基于 Wi-Fi 的低功耗懒人开关—— “ESP32-C3 管灯熊猫”。将智能的 “ESP32-…...

前端学习路线指南:从入门到精通【①】
前言 作为一个前端开发者,学习前端技术是必不可少的。然而,由于前端领域的广阔和不断演进的技术栈,对于初学者来说可能会感到困惑。本篇文章将为你提供一个清晰的前端学习路线,帮助你系统地掌握前端开发技能,并成为一名…...

Flash模拟EEPROM原理浅析
根据ST的手册,我们可以看到,外挂EEPROM和Dflash模拟EEPROM,区别如下: 很明显,模拟EEprom的写入速度要远远快于外挂eeprom(有数据传输机制); 其次,外挂EEPROM不需要擦除即可实现写入数据…...

Typora 最新激活方法
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式,其目标是实现易读易写。而Typora则是一个非常不错的Markdown编辑器,它的界面非常的简洁直观,并且功能各…...

jenkins如何安装?
docker pull jenkins/jenkins:lts-centos7-jdk8 2.docker-compose.yml version: 3 services:jenkins:image: jenkins/jenkins:lts-centos7-jdk8container_name: my-jenkinsports:- "8080:8080" # 映射 Jenkins Web 界面端口volumes:- jenkins_home:/var/jenkins_h…...

从零开始的LINUX(三)
bc:进行浮点数运算 uname:查看当前的操作系统 ctrlc:中止当前正在执行的程序 ctrld:退出xshell shutdown:关机 reboot:重启 shell外壳: 作用:1、命令解释(将输入的程序…...

CleanMyMac2024永久免费版Mac系统磁盘清理工具
Cleanmymac对很多用户来说已经非常熟悉了,因为在网上如果你搜寻有关清理mac系统方面的软件时,占比非常多的会是cleanmymac的相关消息。许多刚从Windows系统转向Mac系统怀抱的用户,一开始难免不习惯,因为Mac系统没有像Windows一样的…...

HashSet 元素不重复
HashSet通过底层使用HashMap来保证元素不重复。具体来说,HashSet内部维护一个HashMap,其中元素存储在HashMap的key上,而所有的value都指向同一个共享的内部对象。在存储元素时,HashSet会根据元素的hashCode值来确定其在HashMap中的…...

基于SpringBoot的二手车交易系统的设计与实现
目录 前言 一、技术栈 二、系统功能介绍 管理员功能实现 商家管理 公告信息管理 论坛管理 商家功能实现 汽车管理 汽车留言管理 论坛管理 用户功能实现 汽车信息 在线论坛 公告信息 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 如今社会上各行…...

最短路径:迪杰斯特拉算法
简介 英文名Dijkstra 作用:找到路中指定起点到指定终点的带权最短路径 核心步骤 1)确定起点,终点 2)从未走过的点中选取从起点到权值最小点作为中心点 3)如果满足 起点到中心点权值 中心点到指定其他点的权值 < 起…...

基于UDP/TCP的网络通信编程实现
小王学习录 今日鸡汤Socket套接字基于UDP来实现一个网络通信程序DatagramSocket类DatagramPacket类基于UDP的服务器端代码基于UDP的客户端代码基于TCP来实现一个网络通信程序ServerSocket类Socket类基于TCP的服务器端代码基于TCP的客户端代码优化之后的服务器端代码补充TCP长短…...

springboot启动报错
...

Python中的split()函数
函数:split() Python中有split()和os.path.split()两个函数,具体作用如下: split():拆分字符串。通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list) os.path.split():…...

大数据-玩转数据-Python Sftp Mysql 数据
一、需求描述 1、从Mysql数据库表下载数据到服务器; 2、将数据已csv文件格式存储并对数据格式进行处理(添加表头,表头和数据均用竖线分隔符隔开,末尾也加分割符); 3、文件路径文件夹以天为单位,…...

Selenium3-当元素通过@FindBy获取时,返回元素为null
报错: 在获取元素的js属性时一直获取不到,报空指针,定位到元素时,发现是FindBy的元素没有找到 解决方法: 在page类的构造函数中加上了 界面初始化,让元素先隐式加载,这样就不会出现返回元素为空的情况辣 PageFactory…...

JWT详解解读读
📑前言 本文主要是jwt解读文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 🌄每日一句:努力一点&#…...

一文详解如何从 Oracle 迁移数据到 DolphinDB
Oracle 是一个广泛使用的关系型数据库管理系统,它支持 ACID 事务处理,具有强大的安全性和可靠性,因此被广泛应用于各种企业级应用程序。但是,随着数据规模的增加和业务需求的变化,Oracle 的一些限制和缺点也逐渐暴露出…...

负载均衡--Haproxy
haproxy 他也是常用的负载均衡软件 nginx 支持四层转发,七层转发 haproxy也可以四层和七层转发 haproxy:法国人开发的威利塔罗在2000年基于C语言开发的一个开源软件 可以支持一万以上的并发请求 高性能的tcp和http负载均衡2.4 1.5.9 haproxy&#…...

股票价格预测 | 融合CNN和Transformer以提升股票趋势预测准确度
一 本文摘要 股票价格往往很难预测,因为我们很难准确建模数据点之间的短期和长期时间关系。卷积神经网络(CNN)擅长找出用于建模短期关系的局部模式。然而,由于其有限的观察范围,CNN无法捕捉到长期关系。相比之下,Transformer可以学习全局上下文和长期关系。本文提出了一…...

QMI8658A_QMC5883L(9轴)-EVB 评估板
1. 描述 QMI8658A_QMC5883L(9轴)-EVB 评估板是一款功能强大的9轴IMU传感器,它利用了QMA8658A 内置的3轴加速度计和3轴陀螺仪,同时结合QMC5883L的3轴地磁数据,来测量物体在三维空间中的角速度和加速度(严格意义上的IMU只为用户提供…...

vue2+antd——实现动态菜单路由功能——基础积累
vue2antd——实现动态菜单路由功能——基础积累 实现的需求:效果图:登录接口处添加以下代码loadRoutes方法内容如下: 最近在写后台管理系统,遇到一个需求就是要将之前的静态路由改为动态路由,使用的后台框架是…...

代码随想录算法训练营第三十八天丨 动态规划part01
动态规划理论基础 动态规划刷题大纲 什么是动态规划 动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的&a…...

关于集合遇到的坑
public void invoke(ComparisonSpotEvaluationResultsExcel comparisonSpotEvaluationResultsExcel, AnalysisContext analysisContext) {/*** 记录行号码*/ReadRowHolder readRowHolder analysisContext.readRowHolder();Integer rowIndex readRowHolder.getRowIndex();Stri…...

需要下微信视频号视频的小伙伴们看过来~
随着视频号的热度越来越大,下载视频号视频的需求也开始增加啦,今天给大家给分享几个简单实用的下载方法,总有一个你能用上的! 一、犀牛视频下载 犀牛视频下载器可以直接解析并下载视频号短视频。您只需转发视频到机器人即可下载。…...