通过字节码分析this关键字以及异常表的重要作用
在之前的字节码分析中缺少对异常的介绍,这次主要来对字节码异常表相关的东东进行一个学习,下面先来编写一个相关异常的小程序:
接着编译来看用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中】。
接着来看一下locals,为啥有4个局部变量呢?下面来分析一下:
1、当然就是隐含的this啦,上面分析stack中标明处有说明。
2、当然就是is喽,如下:
3、当然就是serverSocket喽:
4、那它倒底是啥呢?貌似咱们能见到局部变量就木有了,其实这个局部变量是位于catch当中的,如下:
也就是如果抛出了异常,那么最终这三个异常就会产生一个局部变量,如果不抛出异常,那么这个最多4个局部变量中最终只会使用3个局部变量。
最后再来看一下statck=3,也就是这个方法最多能往栈中压入3个元素,关于栈在之后还会详述的,这里有个基本印象。
接着来则到了该篇要讨论的核心话题:异常,对应方法的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到指定的位置进行异常处理,大至看一下:
具体异常相关的分析下次再继续。
通过字节码分析this关键字以及异常表的重要作用的更多相关文章
- 通过字节码分析this关键字以及异常表的作用
1.创建MyTest3类 public class MyTest3 { public void test(){ try { InputStream is = new FileInputStream(& ...
- 通过字节码分析Java异常处理机制
在上一次[https://www.cnblogs.com/webor2006/p/9691523.html]初步对异常表相关的概念进行了了解,先来回顾一下: 其源代码也贴一下: 下面来看一下jclas ...
- JVM-String比较-字节码分析
一道String字符串比较问题引发的字节码分析 public class a { public static void main(String[] args)throws Exception{ } p ...
- Java并发编程原理与实战八:产生线程安全性问题原因(javap字节码分析)
前面我们说到多线程带来的风险,其中一个很重要的就是安全性,因为其重要性因此,放到本章来进行讲解,那么线程安全性问题产生的原因,我们这节将从底层字节码来进行分析. 一.问题引出 先看一段代码 packa ...
- Python_Tips[2] -> 函数延后估值及字节码分析
函数延后估值及字节码分析 在一个循环中定义了函数 f 但是并未对其进行调用,在循环结束后调用,此时i值为3故最终3个函数输出均为9.而非1, 4, 9. 这是由于在定义闭包函数 f 时,传入变量 i, ...
- Java字节码分析
目录 Java字节码分析 查看字节码详细内容 javap 实例分析 Java字节码分析 对于源码的效率,但从源码来看有时无法分析出准确的结果,因为不同的编译器版本可能会将相同的源码编译成不同的字节码, ...
- 通过字节码分析java中的switch语句
在一次做题中遇到了switch的问题,由于对switch执行顺序的不了解,在这里简单的通过字节码的方式理解一下switch执行顺序(题目如下): public class Ag{ static pub ...
- Java finally语句到底是在return之前还是之后执行(JVM字节码分析及内部体系结构)?
之前看了一篇关于"Java finally语句到底是在return之前还是之后执行?"这样的博客,看到兴致处,突然博客里的一个测试用例让我产生了疑惑. 测试用例如下: public ...
- 字节码分析finally块对return返回值的影响
直接进入主题.看如下代码: public int test(){ int i=0; try { i=1; return i; } catch (Exception e) { i=2; return i ...
随机推荐
- 20190722java学习习惯小结
1.周一——周六: 学习: 周日: 巩固练习测试. 2.java 大数据. python 人工智能 .. 3.写技术博客! 4.python应用: 人工智能.web开发.自动化运维.数据分析.爬虫.游 ...
- 【数据库开发】在Windows上和Linux上配置MySQL的过程
[数据库开发]在Windows上和Linux上配置MySQL的过程 标签(空格分隔): [编程开发] 首先是在Windows上尝试用QT进行MySQL数据库开发,结果总出现driver不能load的错 ...
- Andrew Ng机器学习课程13
Andrew Ng机器学习课程13 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 引言:主要从一般的角度介绍EM算法及其思想,并推导了EM算法的收敛性.最后 ...
- easyui中combobox下拉内容进行分组
需求:对combobox下拉内容进行分组. 效果样式: 代码: valueField:'paymethod_name', textField:'paymethod_name', data:[{ &qu ...
- SpringBoot+Vue前后端分离,使用SpringSecurity完美处理权限问题
原文链接:https://segmentfault.com/a/1190000012879279 当前后端分离时,权限问题的处理也和我们传统的处理方式有一点差异.笔者前几天刚好在负责一个项目的权限管理 ...
- Calibre 和 Kindle 配合的使用方法
1. 前言 使用"Calibre"软件,把网上下载的电子书转换成适合kindle阅读的格式. 2. 使用经验总结 2.1 首行缩进.段落间距设置 2.2 输出为mobi格式设置 2 ...
- docker&k8s-配置/常用命令
kubectl delete deployment,ingress,svc demo-mml-jp-ylmopt-web-1 -n demo-mml #删除预生产环境mml组ylmopt-web ...
- MySQL部分2
- Luogu5327 ZJOI2019语言(树上差分+线段树合并)
暴力树剖做法显然,即使做到两个log也不那么优美. 考虑避免树剖做到一个log.那么容易想到树上差分,也即要对每个点统计所有经过他的路径产生的总贡献(显然就是所有这些路径端点所构成的斯坦纳树大小),并 ...
- codefroce 854 A.Fraction
题解:贪心,每次从能够出发的飞机中取一个最大的就好啦,用一个队列维护一下~ ac代码: #include <cstdio> #include <iostream> #inclu ...