java字节码

1、“一处编译处处运行”

    缘由就是字节码,因为不一样的平台编译出来的机器码0,1是不一样的,java采用不直接编译成机器码(0,1)而是把他们编译成字节码。再由不一样平台上的JVM翻译成对应平台的机器码(0,1)。现在,JVM也再也不只支持Java,由此衍生出了许多基于JVM的编程语言,如Groovy, Scala, Koltin等等。java

 

 

 而字节码命令所能提供的语义描述能力是要明显强于Java自己的,因此有其余一些一样基于JVM的语言能提供许多Java所不支持的语言特性。编程

2、如何看.class文件的十六进制文件格式数组

 

 

 用NotePad++直接打开显示乱码,咱们点开插件--插件管理。而后选择上面标记的地方,而后点安装。编程语言

安装后从新打开.class文件,咱们发现仍是乱码。点插件---HEX-Editor而后选择View in HEX就能够了ide

3、如何看字节码文件,咱们可使用JDK提供的javap命令进行反编译.class,具体用法以下。实际过程当中咱们直接利用IDE看就能够了,例如IDEA直接选中java文件而后View---Show Bytecode就能够看了(首先这个java文件得编译,没有编译在Build中选从新编译一下便可)ui

四:解读字节码this

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
}
View Code

分析上面代码咱们能够获得,52是版本号表明java8,由于java的版本号从45开始,除1.0和1.1都是使用45.x外,之后每升一个大版本,版本号加一。也就是说,编译生成该class文件的jdk版本为1.8.0。spa

大多数的基本数据类型用其首字母大写 (除了long 类型用J,boolean用Z),引用类型用L表示而且以;结束。变量名会在后面写。方法返回值类型中多了V(void)。init方法返回值为V。init方法除了执行构造方法,还会进行初值的赋值等例如咱们上面给一个变量赋一个初值,那么动做也是在这里执行的。从主方法的参数咱们能够看出数组用[lxx类型.   二位数组[[L依次类推。.net

分析上面的构造方法:插件

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