invokespecial指令

LingLee_荊棘鳥發表於2017-08-07

new一個物件包括:類是否載入、為物件分配記憶體、併發處理、記憶體空間初始化、物件設定等步驟,當然new之後有時候會執行<init>,這主要依據位元組碼中是否包含invokespecial指令。下面主要說一下該指令


主要目的:得到物件存在堆中的地址,這樣就可以用當前類,父類,父父類,即繼承層的所有物件

                    把繼承層的所有物件的資料和方法為自己當前物件使用


描述一、The two types of compiler-generated methods that may appear in class files are instance

initialization methods (named <init) and class initialization methods  (named <clinit)

編譯時產生兩種型別方法:

          1、例項初始化方法<init (),就是編譯器為例項變數存放程式碼的地方。

                如果一個類沒有預設無引數的構造器,編譯器自動產生一個<init () 方法(在所有.class檔案中)。

           2、類初始化方法<clinit()  

              1>class variable initializers   static int size = 3 * (int) (Math.random() * 5.0);

              2>static initializers 

                static int size;
               static {size = 3 * (int) (Math.random() * 5.0);size = 3 * (int) (Math.random() * 5.0);

   哪麼什麼時候呼叫呢:1、類初始化方法 :在 load 一個類之後,jvm  就會呼叫  <clinit()   進行初始化值

                                            1、例項初始化:當建立一個類的例項時(new)

一般以變數的形式出現在原始檔中:

一、例項變數(the object's instance variables)和類變數(classvariables)

                      例項變數預設呼叫的方法:<init

                      類變數(帶static)預設呼叫方法:<clinit

二、兩種變數存在地方:

                 1、類成員裡面

                 2、方法裡面

三、  例子,Son .init ()-----Parent.init(),Parent.init()---object.init();           

  1、類成員例項變數 instansV  的方法:因為父,子類都沒有建構函式,按理說,這是一個繼承層呼叫方法,一直會調到父類object 物件為止,

           這裡Parent<int> 沒有呼叫 object  .<init>:()V 方法,留給父類Parent.class 類去呼叫。

  2、Son程式執行過程:  

           

     1》load:裝入son.class

            第一:run Son application,jvm 根據 Son 找到Son.class,並讀入

            第二:Jvm 取出 Son. 類定義資料the constant pool,main()方法的指令bytecodes ,並存入 methode area,

    2》Link:把常量池的所有項(類變數),分配記憶體空間,並設定一個預設值。

           這個類沒有類變數,只有一個例項變數,因為物件還不需要建立,等建立物件後,再來分配例項變數instansV。

   3》initialize:初始化:就是設定實實在在的值。

        沒有類變數,也不需要初始化。

   3>Jvm 呼叫 main() 方法,開始執行Main()方法,解釋bytecodes 指令,同時維護指向the constant pool的指標。      

         0: new           #1                  // class Son

              2: indexbyte1, indexbyte2 :Constant pool#1,#2 來確定類,建立一個物件,MethodinstansV壓入operand stack

  

         3: dup
         4: invokespecial #12                 // Method "<init>":()V
         7: astore_1
         8: return


 2、main()方法裡的例項變數:和上面一樣,只呼叫一次 Son. "<init>":()V

     4: invokespecial #12                 // Method "<init>":()V

public class Parent {
}

public class Son extends Parent {
   Son  instansV=new Son();   //類成員例項變數,objref

  static void main(String[] arg)
  {
 Son MethodinstansV=new Son();//方法裡面例項變數 
 
  }
}

 javap -verbose -c -l -constants Son.class

Constant pool:
   #1 = Class              #2             // Son
   #2 = Utf8               Son
   #3 = Class              #4             // Parent
   #4 = Utf8               Parent
   #5 = Utf8               instansV
   #6 = Utf8               LSon;
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Methodref          #3.#11         // Parent."<init>":()V
  #11 = NameAndType        #7:#8          // "<init>":()V
  #12 = Methodref          #1.#11         // Son."<init>":()V
  #13 = Fieldref           #1.#14         // Son.instansV:LSon;
  #14 = NameAndType        #5:#6          // instansV:LSon;
  #15 = Utf8               LineNumberTable
  #16 = Utf8               LocalVariableTable
  #17 = Utf8               this
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               arg
  #21 = Utf8               [Ljava/lang/String;
  #22 = Utf8               MethodinstansV
  #23 = Utf8               SourceFile
  #24 = Utf8               Son.java
{
  Son instansV;
    descriptor: LSon;
    flags:

  public Son();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0://
         1: invokespecial #10                 // Method Parent."<init>":()V
         4: aload_0
         5: new           #1                  // class Son
         8: dup
         9: invokespecial #12                 // Method "<init>":()V
        12: putfield      #13                 // Field instansV:LSon;
        15: return
      LineNumberTable:
        line 2: 0
        line 3: 4
        line 2: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  this   LSon;


  static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #1                  // class Son
         3: dup
         4: invokespecial #12                 // Method "<init>":()V
         7: astore_1
         8: return
      LineNumberTable:
        line 7: 0
        line 9: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0   arg   [Ljava/lang/String;
            8       1     1 MethodinstansV   LSon;
}
Parent.class
   #1 = Class              #2             // Parent
   #2 = Utf8               Parent
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LParent;
  #14 = Utf8               SourceFile
  #15 = Utf8               Parent.java
{
  public Parent();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8         // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 2: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LParent;
}



四、指令說明
      
助記符  opcode (hex) opcode(bit)   other bytes stack() [before]---[after] 功能
new bb 1011 1011 2: indexbyte1, indexbyte2 → objectref create new object of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2)
aload_0 2a 0010 1010   → objectref load a reference onto the stack from local variable 0
invokespecial b7 1011 0111 2: indexbyte1, indexbyte2 objectref, [arg1, arg2, ...] → result invoke instance method on object objectref and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2)
  Son  instansV=new Son();   //類成員例項變數,objref

1、aload_0:push objectref 入 operand stack, Son ,表示將instansV 放入堆疊中。

 2、 invokespecial  #10 :即物件instansV 的地址(堆中地址,堆中有地址指向method area)。

           表示將instansV 放入堆疊中,操作之後,把結果 放入堆疊中

     1》  2: indexbyte1, indexbyte2=#10 

      2》 operand stack:壓入objectref ,

      3》然後得出結果,壓入operand stack.

         結果:就是objectref 物件的地址

                  按理說:Parent  類 什麼也沒有,但是它有父類 object,所以會有一些成員資料和方法可以使用

                                 需要分配空間存物件和類資料。      

Mnemonic

         0: aload_0:
         1: invokespecial #10                 // Method Parent."<init>":()V
         4: aload_0
         5: new           #1                  // class Son
         8: dup
         9: invokespecial #12                 // Method "<init>":()V
        12: putfield      #13                 // Field instansV:LSon;
        15: return