天天code运行java代码,却不知道编译后的字节码文件到底是什么?
目标:
- 能读懂一个简单的class文件。
- 对程序的Unsupported major.minor version 54.0异常错误有更清楚的理解。
1. class文件
- 它其实就是一个二进制文件。
- 二进制查看不方便,可以通过nodePad或idea以16进制的形式打开class文件
(两个16进制数是一个字节) - 头四个字节,cafe babe 称为magic number,用来标识这是个java编译成的class字节码文件。
- 后面紧跟着的四个字节分别表示class文件的对应jdk版本号(一个小号,一个主号)
随后的两个字节表示此class文件中常量池中的常量数量(最多可有2的16次方减一个常量,65535)
2. 通过javap命令可以查看class文件里面的指令信息(或使用idea的JClassLib插件),可以帮你分析class里面的内容。
- idea查看class内容更方便:
如,this class 表示当前类的名字,这个名字在常量池的#2( 2号)位置存着呢。
interfaces count 有多少个接口,methods count有多少个方法等 - Constant Pool中是常量池里面的内容
如,常量池中的第一项存的是Methodref info 方法信息,里面是指向其它位置的常量内容,分别在3号和13号位置,存的是方法的类信息和返回值信息。(此处表示的是Object类下面的构造方法)
对应16进制的内容为:
每个常量池内容占多少位,需要查看class格式文档来确定(相当于一个字典):如上述第一个常量是10号,它里面占用四个字节,所以00 03 00 0d就是它的内容。
随后07 是第二个常量,它的号是7.然后去class格式文档里面查看7号指令是谁,它占几个字节。
总结:常量的号+常量的具体内容 组成一个常量
3,分析过常量池的内容,接着看mehtod方法里面的内容
- 比如,方法的code里是java的汇编指令:
具体aload_0 invokespecial #1这些的含义需要去规范文档里找。
0x2a 表示的指令是 aload_0 将this压栈
反编译的内容:
对应的class二进制内容:
2a b7 00 01 b1 这五个字节就是类构造方法的具体实现
4,关于,运行代码时抛出Unsupported major.minor version 54.0错误
- 54的值我们了解了class文件内容,就知道了,它是值1.8jdk版本。如果程序抛出此错误,即表示程序是jdk1.8编译的,但运行的环境是低于1.8的版本。如1.6.
解决方法即是运行版本提高一下就可以了。
5,总结
- class文件结构内容:该文件的编译版本是多少,里面有多少常量,常量是什么,有哪些字段,字段的修饰符是什么,有哪些方法,方法的修饰符是什么,方法的返回值是什么,方法的内容是什么,等等