1、创建MyTest3类
public class MyTest3 { public void test(){ try { InputStream is = new FileInputStream("test.txt"); ServerSocket serverSocket = new ServerSocket(9999); serverSocket.accept(); }catch (FileNotFoundException ex){ }catch (IOException ex){ } catch (Exception ex){ }finally { System.out.println("finally"); } } }
然后生成字节码
D:workspacestudy jvm_demouildclassesjavamaincomexamplejvmytecode>javap -verbose MyTest3.class
Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest3.class Last modified 2019-6-29; size 1068 bytes MD5 checksum a51a76cf80a500bc95a8d3d20f7d2a0e Compiled from "MyTest3.java" public class com.example.jvm.bytecode.MyTest3 SourceFile: "MyTest3.java" minor version: 0 major version: 51 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/example/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/example/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/example/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.example.jvm.bytecode.MyTest3(); 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/example/jvm/bytecode/MyTest3; public void test(); 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 15: 10 line 16: 21 line 24: 26 line 25: 34 line 17: 37 line 24: 38 line 25: 46 line 19: 49 line 24: 50 line 25: 58 line 21: 61 line 24: 62 line 25: 70 line 24: 73 line 26: 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/example/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 */ }
查看test方法
stack=3:表示操作数栈的最大深度为3
locals=4: 声明的局部变量的数目为4
args_size=1: 方法本身接收到的参数的数量
思考1:test方法没有接收参数,但是args_size=1表示接收参数为1 ?
对于Java类中的每一实例方法(非static方法),其在编译后所生成的字节码当中,方法参数的数量总是会比源代码中方法参数的数量多一个(this),它位于方法的第一个参数位置处; 这样,我们就可以在Java的实例方法中使用this来去访问当前对象的属性以及其他方法。
这个操作是在编译期间完成的,即由javac编译期在编译的时候将对this的访问转化为对一个普通实例方法参数的访问,接下来在运行期间,由JVM在调用实例方法时,自动向实例方法传入this参数。所以,在实例方法的局部表里表中,至少会有一个指向当前对象的局部变量。
思考2: locals=4,声明的局部变量的数目为4,分别是哪4个?
this,is, serverSocket,ex
stack=3,操作数栈的最大深度
2、异常表
如下图的三个异常
Java字节码对于异常的处理方式:
1、统一采用异常表的方式来对异常进行处理
2、在jdk1.4.2之前的的版本中,并不是对异常表的方式来对异常进行处理的,而是采用特定的指令方式
3、当异常处理存在finally语句块时,现代化的JVM采取的处理方式是将finally语句块的字节码拼接到每一个catch块后面
换句话说,程序中存在多少个catch块,就会在每一个catch块后面重复多少个finally语句的字节码
然后在方法里抛出异常,
反编译后查看