标签:notepad++ ++ href flags style try 版本 lang str
原因就是字节码,由于不同的平台编译出来的机器码0,1是不同的,java采用不直接编译成机器码(0,1)而是把他们编译成字节码。再由不同平台上的JVM翻译成对应平台的机器码(0,1)。如今,JVM也不再只支持Java,由此衍生出了许多基于JVM的编程语言,如Groovy, Scala, Koltin等等。
而字节码命令所能提供的语义描述能力是要明显强于Java本身的,所以有其他一些同样基于JVM的语言能提供许多Java所不支持的语言特性。
二、如何看.class文件的十六进制文件格式
用NotePad++直接打开显示乱码,我们点开插件--插件管理。然后选择上面标记的地方,然后点安装。
安装后重新打开.class文件,我们发现还是乱码。点插件---HEX-Editor然后选择View in HEX就可以了
三、如何看字节码文件,我们可以使用JDK提供的javap命令进行反编译.class,具体用法如下。实际过程中我们直接利用IDE看就可以了,例如IDEA直接选中java文件然后View---Show Bytecode就可以看了(首先这个java文件得编译,没有编译在Build中选重新编译一下即可)
四:解读字节码
package test; public class ReadBytecode { private boolean bo; private byte b; private char c; private short s; private float f; private double d; private int i; private long l; private Integer id; private String name; public void m1(){} public int m2(){ return 1; } public static void main(String[] args) { } } //字节码 // class version 52.0 (52) // access flags 0x21 public class test/ReadBytecode { // compiled from: ReadBytecode.java // access flags 0x2 private Z bo // access flags 0x2 private B b // access flags 0x2 private C c // access flags 0x2 private S s // access flags 0x2 private F f // access flags 0x2 private D d // access flags 0x2 private I i // access flags 0x2 private J l // access flags 0x2 private Ljava/lang/Integer; id // access flags 0x2 private Ljava/lang/String; name // access flags 0x1 public <init>()V L0 LINENUMBER 8 L0 ALOAD 0 INVOKESPECIAL java/lang/Object.<init> ()V RETURN L1 LOCALVARIABLE this Ltest/ReadBytecode; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x1 public m1()V L0 LINENUMBER 19 L0 RETURN L1 LOCALVARIABLE this Ltest/ReadBytecode; L0 L1 0 MAXSTACK = 0 MAXLOCALS = 1 // access flags 0x1 public m2()I L0 LINENUMBER 21 L0 ICONST_1 IRETURN L1 LOCALVARIABLE this Ltest/ReadBytecode; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x9 public static main([Ljava/lang/String;)V // parameter args L0 LINENUMBER 25 L0 RETURN L1 LOCALVARIABLE args [Ljava/lang/String; L0 L1 0 MAXSTACK = 0 MAXLOCALS = 1 }
分析上面代码我们可以得到,52是版本号代表java8,因为java的版本号从45开始,除1.0和1.1都是使用45.x外,以后每升一个大版本,版本号加一。也就是说,编译生成该class文件的jdk版本为1.8.0。
大多数的基本数据类型用其首字母大写 (除了long 类型用J,boolean用Z),引用类型用L表示并且以;结束。变量名会在后面写。方法返回值类型中多了V(void)。init方法返回值为V。init方法除了执行构造方法,还会进行初值的赋值等例如我们上面给一个变量赋一个初值,那么动作也是在这里执行的。从主方法的参数我们可以看出数组用[lxx类型. 二位数组[[L依次类推。
分析上面的构造方法:
L0 L1是方法中字节码行号依次类推L2 L3。。。
LINENUMBER 字节码偏移量,即字节码和源码行数的偏移量。在发生异常的时候可以找到对应的源码位置(可以通过修改编译参数去掉,去掉的话出现异常编译器不会找到源代码异常发生处)
ALOAD 0 将引用型变量压入栈顶,此处就是把调用的方法压入栈顶
INVOKESPECIAL 调用后面的方法
RETURN 弹栈
LOCALVARIABLE 帧栈中定义的局部变量与源码定义的变量之间的关系。如果没有这项信息(通过修改编译参数可以去掉),别人引用这个方法的时候无法获取参数名称,取而代之的是arg0,arg1这样的占位符。
每个实例方法中,都会有一个默认参数this. LOCALVARIABLE 后第一个参数为参数名称,第二个参数类型,第三第四个参数为这个参数在字节码中的可见行范围,最后一个参数表示这个参数在这个桢栈中的位置,例如上面的0。
MAXSTACK 最大操作数栈,JVM会根据这个值来分配栈桢中的操作栈深度,上面为1
MAXLOCALS 局部变量所需的存储空间,单位为Slot。Slot为JVM为局部变量分配内存的最小单位,大小为4个字节。这里的局部变量包括方法参数(包括隐藏的this)、方法内的局部变量、try--catch中catch()定义的参数。注意MAXLOCALS 并不一定等于所有局部变量的Slot和,因为局部变量中的Slot可以重用。
分析下面的m1()方法。很简单因为没有执行语句所以直接弹栈,MAXSTACK为0;
分析m2()方法:
ICONST_1 将int型1推送到栈顶
IRETURN 从当前方法返回int型数据
分析主方法:由于是static 方法所以不会有this
更多字节码指令查询:https://blog.csdn.net/zqz_zqz/article/details/79484757
标签:notepad++ ++ href flags style try 版本 lang str
原文地址:https://www.cnblogs.com/chengxuyuan-liu/p/11603899.html