当前位置:网站首页>IDEA下如何查看字节码?

IDEA下如何查看字节码?

2020-12-07 13:01:13 用户1516716

本篇文章教大家IDEA中查看字节码的三个方法 以及 jdk对字符串拼接、自动装箱和拆箱的操作过程。

首先要知道jdk、jre、jvm三者之间的关系:

JDK:Java 开发工具包,同时还包含了编译java源码的编译器javac,供开发使用。 JRE:Java 运行时环境,一些基本类库,供运行使用。 JVM:Java 虚拟机。它只认识 xxx.class 这种类型的文件,它能够将 class 文件中的字节码指令进行识别并针对不同操作系统向上的 API 完成动作。

Java程序的大致执行流程如下:

java程序执行流程

所以说,jvm 是 Java 能够跨平台的核心。

新建一个Test.java 文件,并编译。下面进入正题,介绍三种方法查看 字节码。

1、使用 JDK 自带 的 javap

javap是jdk自带的一个反汇编工具,可用于查看编译后的字节码。

在编译完成后,定位到你的 .class 文件

但是要看这个字节码,就很麻烦,需要先编译。每次都要找到这个.class文件,然后输入 javap -c xxx.class

那有什么便捷的方法?

当然是有的。

打开 Settings ——》External Tools

name:插件的名字,我写了 MyjavapProgram:插件路径,我这里是 E:\JDK1.8\bin\javap.exe,按照你本地路径写即可。Arguments:参数,直接写 -c FileNameWithoutExtension.classWorking directory:class的输出目录,直接写 OutputPath\FileDirRelativeToSourcepath

点击 OK ,然后选中 你的 .java 源文件,点击 Tools——》External Tools ——》Myjavap

以上就可以很方便地看到控制台输出了字节码。

2、IDEA 自带 show byteCode

点击一下你的 .java 源文件 ,然后 点击菜单栏 View ——》Show byteCode

然后就会弹出一个字节码的窗口。

3、jclasslib 插件

在插件市场搜索 jclasslib,点击安装。

重启IDEA。

菜单栏 View——》Show Bytecode With jclasslib

字节码含义

下面说一下字节码的含义。

更多字节码的指令解释可参考:https://blog.csdn.net/qq_31407255/article/details/88978630

我本地的 Test.java :

public class Test {
    public static void main(String[] args) {
        String a = "I am ";
        String b = "HaC";
        String c = a + b;
        String d = "I am " + "HaC";
        System.out.println(c == d); //false
        Integer i =100; //装箱
        int j = i;  //拆箱
        System.out.println(i == j); //true
    }
}

这个是使用jclasslib的字节码:

 0 ldc #2 <I am >       # JVM采用ldc指令将常量压入栈中
 2 astore_1            # 将栈顶引用类型值保存到局部变量1中,即a
 3 ldc #3 <HaC>
 5 astore_2
 6 new #4 <java/lang/StringBuilder>        # 创建新的对象实例,即c
 9 dup                                  # 复制栈顶一个字长的数据,将复制后的数据压栈。
10 invokespecial #5 <java/lang/StringBuilder.<init>> # 编译时方法绑定调用方法,编译时调用StringBuilder,相当于 new StringBuilder("I am "),下同
13 aload_1                                         # 从局部变量1,即对new StringBuilder("I am ")的引用,装载引用类型值入栈。
14 invokevirtual #6 <java/lang/StringBuilder.append> # 这里调用StringBuilder的appen方法,运行时进行拼接
17 aload_2
18 invokevirtual #6 <java/lang/StringBuilder.append>
21 invokevirtual #7 <java/lang/StringBuilder.toString>    # 最后调用 toString方法,即 "I am HaC".toString
24 astore_3                                         
25 ldc #8 <I am HaC>      # 这里jvm直接优化了,把  d 变成了"I am HaC"
27 astore 4
29 getstatic #9 <java/lang/System.out>
32 aload_3
33 aload 4
35 if_acmpne 42 (+7)
38 iconst_1
39 goto 43 (+4)
42 iconst_0
43 invokevirtual #10 <java/io/PrintStream.println>
46 bipush 100
48 invokestatic #11 <java/lang/Integer.valueOf>        # Integer i =100;装箱,即等于Integer i =Integer.valueOf(100);
51 astore 5
53 aload 5
55 invokevirtual #12 <java/lang/Integer.intValue>   # int j = i; 拆箱,即等于 int j = i.intValue();
58 istore 6
60 getstatic #9 <java/lang/System.out>
63 aload 5
65 invokevirtual #12 <java/lang/Integer.intValue>  # Integer和int比较, Integer自动调用intValue方法,即拆箱
68 iload 6
70 if_icmpne 77 (+7)
73 iconst_1
74 goto 78 (+4)
77 iconst_0
78 invokevirtual #10 <java/io/PrintStream.println>
81 return

所以说,

String c = a + b;
String d = "I am " + "HaC";
System.out.println(c == d); //false

c 是使用了 StringBuilder 进行拼接,最后返回的是堆的内存引用,而 d 是 jvm优化后,直接指向常量池的 "I am HaC",两者是不相等的。

而当 Integer对象 和 int 基本类型 比较的时候,Integer会自动拆箱,转化成 int 类型,比较的是值,两者自然相等。

 Integer i =100; //装箱
 int j = i;  //拆箱
 System.out.println(i == j); //true

本文分享自微信公众号 - IT牧场(itmuch_com)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间: 2020-12-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

版权声明
本文为[用户1516716]所创,转载请带上原文链接,感谢
https://cloud.tencent.com/developer/article/1757182