天天code运行java代码,却不知道编译后的字节码文件到底是什么?

目标:

  • 能读懂一个简单的class文件。
  • 对程序的Unsupported major.minor version 54.0异常错误有更清楚的理解。

1. class文件

  • 它其实就是一个二进制文件。
  • 二进制查看不方便,可以通过nodePad或idea以16进制的形式打开class文件
    (两个16进制数是一个字节)
  • asm java 保存字节码 java字节码文件_java

  • 头四个字节,cafe babe 称为magic number,用来标识这是个java编译成的class字节码文件。
  • 后面紧跟着的四个字节分别表示class文件的对应jdk版本号(一个小号,一个主号)
    随后的两个字节表示此class文件中常量池中的常量数量(最多可有2的16次方减一个常量,65535)
  • asm java 保存字节码 java字节码文件_常量池_02

2. 通过javap命令可以查看class文件里面的指令信息(或使用idea的JClassLib插件),可以帮你分析class里面的内容。

asm java 保存字节码 java字节码文件_asm java 保存字节码_03

  • idea查看class内容更方便:
    如,this class 表示当前类的名字,这个名字在常量池的#2( 2号)位置存着呢。
    interfaces count 有多少个接口,methods count有多少个方法等
  • asm java 保存字节码 java字节码文件_asm java 保存字节码_04

  • Constant Pool中是常量池里面的内容
  • asm java 保存字节码 java字节码文件_asm java 保存字节码_05

如,常量池中的第一项存的是Methodref info 方法信息,里面是指向其它位置的常量内容,分别在3号和13号位置,存的是方法的类信息和返回值信息。(此处表示的是Object类下面的构造方法)

asm java 保存字节码 java字节码文件_16进制_06

asm java 保存字节码 java字节码文件_asm java 保存字节码_07

对应16进制的内容为:

asm java 保存字节码 java字节码文件_16进制_08

每个常量池内容占多少位,需要查看class格式文档来确定(相当于一个字典):如上述第一个常量是10号,它里面占用四个字节,所以00 03 00 0d就是它的内容。

随后07 是第二个常量,它的号是7.然后去class格式文档里面查看7号指令是谁,它占几个字节。

总结:常量的号+常量的具体内容 组成一个常量

asm java 保存字节码 java字节码文件_asm java 保存字节码_09

3,分析过常量池的内容,接着看mehtod方法里面的内容

asm java 保存字节码 java字节码文件_asm java 保存字节码_10

  • 比如,方法的code里是java的汇编指令:
    具体aload_0 invokespecial #1这些的含义需要去规范文档里找。

0x2a 表示的指令是 aload_0 将this压栈

asm java 保存字节码 java字节码文件_常量池_11


asm java 保存字节码 java字节码文件_16进制_12

反编译的内容:

asm java 保存字节码 java字节码文件_常量池_13

对应的class二进制内容:

2a b7 00 01 b1 这五个字节就是类构造方法的具体实现

asm java 保存字节码 java字节码文件_16进制_14

4,关于,运行代码时抛出Unsupported major.minor version 54.0错误

  • 54的值我们了解了class文件内容,就知道了,它是值1.8jdk版本。如果程序抛出此错误,即表示程序是jdk1.8编译的,但运行的环境是低于1.8的版本。如1.6.
    解决方法即是运行版本提高一下就可以了。

5,总结

  • class文件结构内容:该文件的编译版本是多少,里面有多少常量,常量是什么,有哪些字段,字段的修饰符是什么,有哪些方法,方法的修饰符是什么,方法的返回值是什么,方法的内容是什么,等等