在以前的字節碼分析中缺乏對異常的介紹,此次主要來對字節碼異常表相關的東東進行一個學習,下面先來編寫一個相關異常的小程序: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組成,那這四個元素分別表明啥呢?下面來看一下:
其實異常在字節碼中是存在有goto語句的,也就是當發生異常則會goto到指定的位置進行異常處理,大至看一下:
具體異常相關的分析下次再繼續。