文章目录
前言
因为JVM针对各种操作系统和平台都进行了定制,无论在什么平台,都可以通过javac命令将一个.java文件编译成固定格式的字节码(.class文件)供JVM使用。之所以被称为字节码,是因为 .class文件是由十六进制值组成的,JVM以两个十六进制值为一组,就是以字节为单位进行读取
一、Demo原码
package com.java.jvm;
public class Demo1 {
private int a = 1;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
二、字节码文件的产生
1、javac命令产生
在原码所在文件下进入doc命令窗口,使用javac生成
2、idea主动编译或者运行时产生
三、Class文件打开方式
1、使用文本工具打开
内容如下:
2、javap查看字节码文件
javap是JDK自带的反编译工具,可以通过控制台查看字节码文件的内容。适合在服务器上查看字节码文件内容。
直接输入javap查看所有参数。输入javap -v
字节码文件名称 查看具体的字节码信息。如果jar包需要先使用 jar –xvf
命令解压。
3、jclasslib查看字节码文件
jclasslib也有Idea插件版本,建议开发时使用Idea插件版本,可以在代码编译之后实时看到字节码文件内容。
1、打开idea的插件页面,搜索jclasslib
2、选中要查看的源代码文件,选择 视图(View) - Show Bytecode With Jclasslib(在编译好的情况下)
四、字节码文件的组成
1、 基本信息
1)Magic魔数
每个Java字节码文件的前四个字节是固定的,用16进制表示就是0xcafebabe。文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改不影响文件的内容。软件会使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错。
初此之外,还有一些其他格式的魔数如下:
文件类型 | 字节数 |
---|---|
jpj | FFD8FF |
png | 89504E47(文件尾也有要求) |
xml | 3C3F786D6C |
java字节码文件 | CAFEBABE |
2)主副版本号
主副版本号指的是编译字节码文件时使用的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不同版本的标识,一般只需要关心主版本号。
1.2之后大版本号计算方法就是 : 主版本号 – 44,比如主版本号52就是JDK8。
版本号的作用主要是判断当前字节码的版本和运行时的JDK是否兼容。如果使用较低版本的JDK去运行较高版本JDK的字节码文件,无法使用会显示如下错误:
有两种方案:
1.升级JDK版本,将图中使用的JDK6升级至JDK8即可正常运行,容易引发其他的兼容性问题,并且需要大量的测试。
2.将第三方依赖的版本号降低或者更换依赖,以满足JDK版本的要求。建议使用这种方案
3)其他基础信息
其他基础信息包括访问标识、类和接口索引,如下:
2、常量池
常量池存放两大类常量:字面量和符号引用。
字面量: 字面量就是指由字母、数字等构成的字符串或者数值常量。字面量只可以右值出现。
符号引用: 符号引用为指向字面量的索引。
3、字段
字段中存放的是当前类或接口声明的字段信息。
如下图中,定义了两个字段a1和a2,这两个字段就会出现在字段这部分内容中。同时还包含字段的名字、描述符(字段的类型)、访问标识(public/private static final等)。
4、方法
字节码中的方法区域是存放字节码指令的核心位置,字节码指令的内容存放在方法的Code属性中。
5、属性
属性主要指的是类的属性,比如源码的文件名、内部类的列表等。