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

相關文章
相關標籤/搜索