今天起开启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. Linux 学习笔记 1 使用最小的系统,从分区安装系统开始

    我们常用的linux系统在安装过程中大多都省略了对系统进行分区的操作,以至于后期,不了解什么是分区以及分区当中最基本的一些概念, 我们不说最细的知识,只求了解这个过程,那直接步入正题,开始第一节的学习 ...

  2. python 文件读写操作(24)

    以前的代码都是直接将数据输出到控制台,实际上我们也可以通过读/写文件的方式读取/输出到磁盘文件中,文件读写简称I/O操作.文件I/O操作一共分为四部分:打开(open)/读取(read)/写入(wri ...

  3. OS填空题练习

    1.操作系统的基本特征:并发性:共享性:虚拟性:异步性. 2.操作系统的设计目标:方便性:有效性:可扩充性:开放性. 3.操作系统的主要功能:处理机管理:存储器管理:设备管理:文件管理:用户接口. 4 ...

  4. K8S从入门到放弃系列-(3)部署etcd集群

    摘要:etcd 是k8s集群最重要的组件,用来存储k8s的所有服务信息, etcd 挂了,集群就挂了,我们这里把etcd部署在master三台节点上做高可用,etcd集群采用raft算法选举Leade ...

  5. VC++:创建,调用MFC动态链接库(扩展DLL)

    概述 DLL(Dynamic Linkable Library)动态链接库,Dll可以看作一种仓库,仓库中包含了可以直接使用的变量,函数或类. 仓库的发展史经历了"无库" ---& ...

  6. root用户和sudo使用root权限的区别(转)

    百度百科:https://baike.baidu.com/item/sudo/7337623?fr=aladdin sudo指令 功能: 以root的身分执行命令 语法: sudo 其他指令 用户: ...

  7. eclipse智能提示报错(to avoid the message, disable the...)

    然后这里可能会再报别的错误  我的做法是   再重新将 code recommenders 打开 ********************************** 为什么会出现 这样错误呢 ? 简 ...

  8. CCF 201809-1 卖菜

    题目: 问题描述 在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜. 第一天,每个商店都自己定了一个价格.店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己 ...

  9. Angular 调试

    我们新建一个项目.执行 ng server 会启动一个网站. 1. 执行 where ng .看看ng 是什么. D:\Abp学习\angular\Mytest>where ng C:\User ...

  10. 【原创】大叔经验分享(86)hive和mysql数据互导

    hive和mysql数据互导,首先想到的是sqoop,并且可以和调度框架(比如oozie等)配合配置定时任务,还有一种更简单的方式是通过spark-sql: CREATE OR REPLACE TEM ...