今天起开启JVM的新的知识学习篇章----Java的字节码,那学习Java字节码有啥用呢?我们知道Java是跨平台的一门语言,编写一次到处运行,而支撑着这个特性的根基为两点:JVM和.class字节码文件,java在不同的平台上编译生成的.class文件是一模一样的,而JVM针对不同的操作系统会有不同的JVM,也就是JVM其实并非是跨平台的,而生成的.class文件其实是一个二进制文件,该文件并非是给人看的,而是给机器看的,所以肯定是看不懂的,但是针对字节码JVM是有规范定义的,而如今基于JVM的语言也越来越多,如:scala,groovy,kotlin等,虽说语言不同但是编译出来的字节码文件都是符合JVM规范的,也就是对于JVM来说不管咱们用的是哪种语言编写的,只关心字节码文件是否符合字节码的规范,只要符合了就可以加载运行。另外在了解了字节码文件之后,对于很多深层次的东东【如synchronized关键字、volatile关键字】就会了解得更加透彻了,当然啦,学习它当然是非常之枯燥的,但是这个枯燥是为了让自己学得更加的通透,一切都是值得的,所以下面硬着头皮开始:

先编写一个简单的代码作为字节码学习的开端,如下:

然后编译生成字节码文件:

然后双击打开它:

【提示】:当我们完全搞懂了字节码的东东之后,也就搞明白了这些反编译工具的运行机制了,为什么从.class文件能过翻译成源代码呢?

可以看到该反编译还是挺强大的,几乎跟源代码看到的是一样的,这个对于咱们来观察字节码文件不太方便,所以换用java命令来查看一下,这里用javap命令,如下:

貌似用这个命令执行之后看到的信息没有啥价值,所以这里加一个参数再来看:

xiongweideMacBook-Pro:classes xiongwei$ pwd
/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes
xiongweideMacBook-Pro:classes xiongwei$ javap -c com/jvm/bytecode/MyTest1
Compiled from "MyTest1.java"
public class com.jvm.bytecode.MyTest1 {
public com.jvm.bytecode.MyTest1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field a:I
9: return public int getA();
Code:
0: aload_0
1: getfield #2 // Field a:I
4: ireturn public void setA(int);
Code:
0: aload_0
1: iload_1
2: putfield #2 // Field a:I
5: return
}

另外还有一个参数可以看到更加详细的字节码信息,如下:

xiongweideMacBook-Pro:classes xiongwei$ pwd
/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes
xiongweideMacBook-Pro:classes xiongwei$ javap -c com/jvm/bytecode/MyTest1
Compiled from "MyTest1.java"
public class com.jvm.bytecode.MyTest1 {
public com.jvm.bytecode.MyTest1();
xiongweideMacBook-Pro:classes xiongwei$ pwd
/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes
xiongweideMacBook-Pro:classes xiongwei$ javap -verbose com/jvm/bytecode/MyTest1
Classfile /Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes/com/jvm/bytecode/MyTest1.class
Last modified Aug 2, 2018; size 479 bytes
MD5 checksum 4616561f95c24d6b04ea48a360437b8d
Compiled from "MyTest1.java"
public class com.jvm.bytecode.MyTest1
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#20 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#21 // com/jvm/bytecode/MyTest1.a:I
#3 = Class #22 // com/jvm/bytecode/MyTest1
#4 = Class #23 // java/lang/Object
#5 = Utf8 a
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/jvm/bytecode/MyTest1;
#14 = Utf8 getA
#15 = Utf8 ()I
#16 = Utf8 setA
#17 = Utf8 (I)V
#18 = Utf8 SourceFile
#19 = Utf8 MyTest1.java
#20 = NameAndType #7:#8 // "<init>":()V
#21 = NameAndType #5:#6 // a:I
#22 = Utf8 com/jvm/bytecode/MyTest1
#23 = Utf8 java/lang/Object
{
public com.jvm.bytecode.MyTest1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field a:I
9: return
LineNumberTable:
line 3: 0
line 4: 4
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/jvm/bytecode/MyTest1; public int getA();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field a:I
4: ireturn
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jvm/bytecode/MyTest1; public void setA(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: iload_1
2: putfield #2 // Field a:I
5: return
LineNumberTable:
line 11: 0
line 12: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/jvm/bytecode/MyTest1;
0 6 1 a I
}
SourceFile: "MyTest1.java"

下面大概来看一下打印的信息:

好,上面大致分析一下,反正目前也看不懂,接下来用二进制的分析工具来查看一下该字节码文件,有个感性的认识,在mac平台上推荐使用hexfiend,官网:http://ridiculousfish.com/hexfiend/

下载安装好既可,打开它:

将咱们的字节码文件用它打开:

目前显示的是四个字节进行分隔的:

为了更于未来的学习,将其设置为一个字节一显示,如下:

那对于这一串十六进制的魔鬼数字怎么就可以对应到javap命令所看到的结果那样呢?其实是有一定的规则的,下面先来说一下其规则:

1、使用javap -verbose命令分析一个字节码文件时,将会分析该字节码文件的魔数、版本号、常量池、类信息、类的构造方法、类中的方法信息、类变量与成员变量等信息。

2、魔数:所有的.class字节码文件的前4个字节都是魔数,魔数值为固定值:0xCAFEBABE。

回到咱们的二进制中来看是不是这样:

搜嘎,完来是这么回事,如果一个字节码文件不是这个魔数开头的话JVM则会认为是一个不合法的字节码文件。那问题来了,为啥要以“CAFEBABE”开头呢?CAFE是“咖啡”的意思,而BABE是“宝贝”的意思,翻译过来就是“咖啡宝贝”,而java本来就是咖啡的意思啦,而有个细节可以看到:

Java字节码文件结构剖析的更多相关文章

  1. Java字节码深度剖析

    Java字节码文件查看 我们有一个类Test01,具体内容如下: package bytecode; public class Test01 { private int i = 0; public i ...

  2. 从 HelloWorld 看 Java 字节码文件结构

    很多时候,我们都是从代码层面去学习如何编程,却很少去看看一个个 Java 代码背后到底是什么.今天就让我们从一个最简单的 Hello World 开始看一看 Java 的类文件结构. 在开始之前,我们 ...

  3. 深入理解JVM-java字节码文件结构剖析(练习解读字节码)

    public class MyTest2 { String str = "Welcome"; private int x = 5; public static Integer in ...

  4. 深入理解JVM-java字节码文件结构剖析(1)

    public class MyTest1 { private int a = 1; public int getA() { return a; } public void setA(int a) { ...

  5. Java字节码文件结构---概述

    一.Class文件的结构概述: 是一连串的字节流(以自节为基本单位划分),里面包含的数据项按照固定的次序依次排列组成Class文件,文件内部不含分割符 当数据项的长度大于1B时候,按照高位在前的方式存 ...

  6. Java字节码常量池深入剖析

    继续来分析Java字节码,上一节分析了魔数的规则,接下来继续往下分析,其上次总结的规则也一起贴出来: 1.使用javap -verbose命令分析一个字节码文件时,将会分析该字节码文件的魔数.版本号. ...

  7. JVM基础系列第5讲:字节码文件结构

    温馨提示:此篇文章长达两万字,图片50多张,内容非常多,建议收藏后再看. 前面我们说到 Java 虚拟机使用字节码实现了跨平台的愿景,无论什么系统,我们都可以使用 Java 虚拟机解释执行字节码文件. ...

  8. <JVM中篇:字节码与类的加载篇>01-Class字节码文件结构

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...

  9. 【JVM源码解析】模板解释器解释执行Java字节码指令(上)

    本文由HeapDump性能社区首席讲师鸠摩(马智)授权整理发布 第17章-x86-64寄存器 不同的CPU都能够解释的机器语言的体系称为指令集架构(ISA,Instruction Set Archit ...

随机推荐

  1. Egret入门学习日记 --- 第三篇 (书中 3.4 内容)

    第三篇 (书中 3.4 内容) 今天还是要把昨天项目运行后,EXML文件里的界面没有出现的问题解决了才行. 去了群里,没人回.去了官网看文档,看不懂. 不过倒是看到了一个好东西: 还挺便宜啊,一个月要 ...

  2. 不用第三方软件–一键开关笔记本电脑wifi热点的批处理

    笔者有点洁癖啊,很强烈抵制那些辣鸡流氓软件的.用笔记本开个wifi还要装东西,搞不好给我塞一堆东西,我勒个fdkshgkhalsh,. 下面就是集设置密码与开关wifi于一身的bat,这个批处理能简化 ...

  3. 纯小白安装MongoDB的图形界面工具adminMongo

    今天安了两个MongoDB的图形界面工具,robot3和adminMongo,至于为什么安两个....因为网上说啥好用的都有,我也很迷... 安装adminMongo的时候...和正常软件安装流程不太 ...

  4. js中实现base64加密、解密

    //base64加密 解密 /* //1.加密 var result = Base.encode('125中文'); //--> "MTI15Lit5paH" //2.解密 ...

  5. rewrite重写基础实列

    nginx 重写 rewrite 基础及实例 nginx rewrite 正则表达式匹配 大小写匹配 ~ 为区分大小写匹配 ~* 为不区分大小写匹配 !~和!~*分别为区分大小写不匹配及不区分大小写不 ...

  6. windows和linux环境下使用google的glog日志库

    一.概述 glog是google推出的一款轻量级c++开源日志框架,源码在github上,目前最新release版本是v0.3.5. githut地址:https://github.com/googl ...

  7. 变量————if语句——结构使用

    1简述变量的命名规范 变量是以字母 数字 下划线组合而成 不能以数字开头 不能使用python中的关键字命名 变量要具有可描述性 区分大小写 name变量是什么数据类型通过代码检测 name = in ...

  8. docker 实践一:简介和安装

    docker 的简介 docker 绝对是这几年来的重量级开源软件,它是使用 Go 实现的开源容器项目,分属于虚拟化技术. docker 和 虚拟机 docker 作为一种轻量级的虚拟化方式,在运行应 ...

  9. 网络模式: host-only & NAT & 桥接

    基本上,Host-only相当于虚拟机和宿主机通过交叉线相连:NAT,宿主机相当于虚拟机的路由器:桥接,相当于把宿主机和虚拟机同时接到交换机上,然后交换机接到外网. 连接性上说,可参考下表: 连接 宿 ...

  10. Redis键的基本操作

    1.Redis键的键名查询 ·命令名称:KEYS ·语法:KEYS pattern ·Pattern的用法: ? 任意一个字符 * 任意个任意字符 [ae] a或者e [^ae] 除了a和e [a-c ...