經過字節碼分析this關鍵字以及異常表的重要做用

在以前的字節碼分析中缺乏對異常的介紹,此次主要來對字節碼異常表相關的東東進行一個學習,下面先來編寫一個相關異常的小程序:java

接着編譯來看用javap -verbose來查看一下它的字節碼信息:小程序

xiongweideMacBook-Pro:classes xiongwei$ javap -verbose com/jvm/bytecode/MyTest3.class 
Classfile /Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes/com/jvm/bytecode/MyTest3.class
  Last modified Sep 26, 2018; size 1056 bytes
  MD5 checksum 67ac394f07ca1303eb0119b94486d428
  Compiled from "MyTest3.java"
public class com.jvm.bytecode.MyTest3
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #15.#35        // java/lang/Object."<init>":()V
   #2 = Class              #36            // java/io/FileInputStream
   #3 = String             #37            // test.txt
   #4 = Methodref          #2.#38         // java/io/FileInputStream."<init>":(Ljava/lang/String;)V
   #5 = Class              #39            // java/net/ServerSocket
   #6 = Methodref          #5.#40         // java/net/ServerSocket."<init>":(I)V
   #7 = Methodref          #5.#41         // java/net/ServerSocket.accept:()Ljava/net/Socket;
   #8 = Fieldref           #42.#43        // java/lang/System.out:Ljava/io/PrintStream;
   #9 = String             #44            // finally
  #10 = Methodref          #45.#46        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #11 = Class              #47            // java/io/FileNotFoundException
  #12 = Class              #48            // java/io/IOException
  #13 = Class              #49            // java/lang/Exception
  #14 = Class              #50            // com/jvm/bytecode/MyTest3
  #15 = Class              #51            // java/lang/Object
  #16 = Utf8               <init>
  #17 = Utf8               ()V
  #18 = Utf8               Code
  #19 = Utf8               LineNumberTable
  #20 = Utf8               LocalVariableTable
  #21 = Utf8               this
  #22 = Utf8               Lcom/jvm/bytecode/MyTest3;
  #23 = Utf8               test
  #24 = Utf8               is
  #25 = Utf8               Ljava/io/InputStream;
  #26 = Utf8               serverSocket
  #27 = Utf8               Ljava/net/ServerSocket;
  #28 = Utf8               StackMapTable
  #29 = Class              #47            // java/io/FileNotFoundException
  #30 = Class              #48            // java/io/IOException
  #31 = Class              #49            // java/lang/Exception
  #32 = Class              #52            // java/lang/Throwable
  #33 = Utf8               SourceFile
  #34 = Utf8               MyTest3.java
  #35 = NameAndType        #16:#17        // "<init>":()V
  #36 = Utf8               java/io/FileInputStream
  #37 = Utf8               test.txt
  #38 = NameAndType        #16:#53        // "<init>":(Ljava/lang/String;)V
  #39 = Utf8               java/net/ServerSocket
  #40 = NameAndType        #16:#54        // "<init>":(I)V
  #41 = NameAndType        #55:#56        // accept:()Ljava/net/Socket;
  #42 = Class              #57            // java/lang/System
  #43 = NameAndType        #58:#59        // out:Ljava/io/PrintStream;
  #44 = Utf8               finally
  #45 = Class              #60            // java/io/PrintStream
  #46 = NameAndType        #61:#53        // println:(Ljava/lang/String;)V
  #47 = Utf8               java/io/FileNotFoundException
  #48 = Utf8               java/io/IOException
  #49 = Utf8               java/lang/Exception
  #50 = Utf8               com/jvm/bytecode/MyTest3
  #51 = Utf8               java/lang/Object
  #52 = Utf8               java/lang/Throwable
  #53 = Utf8               (Ljava/lang/String;)V
  #54 = Utf8               (I)V
  #55 = Utf8               accept
  #56 = Utf8               ()Ljava/net/Socket;
  #57 = Utf8               java/lang/System
  #58 = Utf8               out
  #59 = Utf8               Ljava/io/PrintStream;
  #60 = Utf8               java/io/PrintStream
  #61 = Utf8               println
{
  public com.jvm.bytecode.MyTest3();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/jvm/bytecode/MyTest3;

  public void test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=4, args_size=1
         0: new           #2                  // class java/io/FileInputStream
         3: dup
         4: ldc           #3                  // String test.txt
         6: invokespecial #4                  // Method java/io/FileInputStream."<init>":(Ljava/lang/String;)V
         9: astore_1
        10: new           #5                  // class java/net/ServerSocket
        13: dup
        14: sipush        9999
        17: invokespecial #6                  // Method java/net/ServerSocket."<init>":(I)V
        20: astore_2
        21: aload_2
        22: invokevirtual #7                  // Method java/net/ServerSocket.accept:()Ljava/net/Socket;
        25: pop
        26: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        29: ldc           #9                  // String finally
        31: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        34: goto          84
        37: astore_1
        38: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        41: ldc           #9                  // String finally
        43: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        46: goto          84
        49: astore_1
        50: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        53: ldc           #9                  // String finally
        55: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        58: goto          84
        61: astore_1
        62: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        65: ldc           #9                  // String finally
        67: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        70: goto          84
        73: astore_3
        74: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        77: ldc           #9                  // String finally
        79: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        82: aload_3
        83: athrow
        84: return
      Exception table:
         from    to  target type
             0    26    37   Class java/io/FileNotFoundException
             0    26    49   Class java/io/IOException
             0    26    61   Class java/lang/Exception
             0    26    73   any
      LineNumberTable:
        line 13: 0
        line 14: 10
        line 15: 21
        line 23: 26
        line 24: 34
        line 16: 37
        line 23: 38
        line 24: 46
        line 18: 49
        line 23: 50
        line 24: 58
        line 20: 61
        line 23: 62
        line 24: 70
        line 23: 73
        line 24: 82
        line 25: 84
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           10      16     1    is   Ljava/io/InputStream;
           21       5     2 serverSocket   Ljava/net/ServerSocket;
            0      85     0  this   Lcom/jvm/bytecode/MyTest3;
      StackMapTable: number_of_entries = 5
        frame_type = 101 /* same_locals_1_stack_item */
          stack = [ class java/io/FileNotFoundException ]
        frame_type = 75 /* same_locals_1_stack_item */
          stack = [ class java/io/IOException ]
        frame_type = 75 /* same_locals_1_stack_item */
          stack = [ class java/lang/Exception ]
        frame_type = 75 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
        frame_type = 10 /* same */
}
SourceFile: "MyTest3.java"

其中重點觀注一下test()方法的信息:數組

其中stack表示這個方法運行的任什麼時候刻所能達到的操做數棧的最大深度;local表示方法執行期間建立的局部變量的數目,包含用來表示傳入的參數的局部變量。args_size表示方法的參數的總個數。
下面首先來解釋一下爲啥args_size等於1,很明顯我們這個方法是一個無參的定義,關於這個在以前的學習中已經解釋過了,這裏再鞏固一下:對於Java類中的每個實例方法(非static方法),其在編譯後所生成的字節碼當中,方法參數的數量老是會比源代碼中方法的參數的數量多一個(this),它位於方法的第一個參數位置處;這樣,咱們就能夠在Java的實例方法中使用this來去訪問當前對象的屬性以及其它方法。這個操做是在編譯期間完成的,既由javac編譯器在編譯的時候將對this的訪問轉化爲對一個普通實例方法參數的訪問,接下來的運行期間,由JVM在調用實例方法時,自動向實例方法傳入該this參數。因此,在實例方法的局部變量表中,至少會有一個指向當前對象的局部變量【也就是會存在於下面要分析的locals中】jvm

接着來看一下locals,爲啥有4個局部變量呢?下面來分析一下:
一、固然就是隱含的this啦,上面分析stack中標明處有說明。ide

二、固然就是is嘍,以下:
學習

三、固然就是serverSocket嘍:
this

四、那它倒底是啥呢?貌似我們能見到局部變量就木有了,其實這個局部變量是位於catch當中的,以下:
spa

也就是若是拋出了異常,那麼最終這三個異常就會產生一個局部變量,若是不拋出異常,那麼這個最多4個局部變量中最終只會使用3個局部變量。code

最後再來看一下statck=3,也就是這個方法最多能往棧中壓入3個元素,關於棧在以後還會詳述的,這裏有個基本印象。server

接着來則到了該篇要討論的核心話題:異常,對應方法的code屬性中exception_table,這裏存放的是處理異常的信息。每個exception_table表項由start_pc、end_pc、handler_pc、catch_type組成,那這四個元素分別表明啥呢?下面來看一下:

  • start_pc和end_pc表示在code數組中的從start_pc到end_pc處(包含start_pc,不包含end_pc)的指令拋出的異常會由這個表項來處理。
  • handler_pc表示處理異常的代碼的開始處。catch_type表示會被處理的異常類型,它指向常量池裏的一個異常表。當catch_type爲0時,表示處理全部的異常。

其實異常在字節碼中是存在有goto語句的,也就是當發生異常則會goto到指定的位置進行異常處理,大至看一下:

具體異常相關的分析下次再繼續。

相關文章
相關標籤/搜索