ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # 简介 **Java字节代码的组织形式** ~~~ 类文件{   OxCAFEBABE,小版本号,大版本号,常量池大小,常量池数组,访问控制标记,当前类信息,父类信息,实现的接口个数,实现的接口信息数组,域个数,域信息数组,方法个数,方法信息数组,属性个数,属性信息数组 } ~~~ 查看编译后的字节码 ~~~ javap -v class文件 ~~~ ~~~ C:\>javap -help 用法: javap <options> <classes> 其中, 可能的选项包括: -help --help -? 输出此用法消息 -version 版本信息 -v -verbose 输出附加信息 -l 输出行号和本地变量表 -public 仅显示公共类和成员 -protected 显示受保护的/公共类和成员 -package 显示程序包/受保护的/公共类 和成员 (默认) -p -private 显示所有类和成员 -c 对代码进行反汇编 -s 输出内部类型签名 -sysinfo 显示正在处理的类的 系统信息 (路径, 大小, 日期, MD5 散列) -constants 显示静态最终常量 -classpath <path> 指定查找用户类文件的位置 -bootclasspath <path> 覆盖引导类文件的位置 ~~~ [https://www.cnblogs.com/frinder6/p/5440173.html](https://www.cnblogs.com/frinder6/p/5440173.html) # javap ~~~ public class Demo { private Long id; private String username; //getter setter .... } ~~~ 通过jdk自带的反编译工具命令 javap 可以查看class文件的字节码信息 ~~~ javac Demo.java javap -verbose Demo ~~~ ~~~ ➜ javac javap -verbose Demo Classfile /Users/jdxia/Desktop/javac/Demo.class Last modified 2019-11-23; size 1339 bytes MD5 checksum eef8986d2c0c4aecf2ac86fa67c97412 Compiled from "Demo.java" public class Demo minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#42 // java/lang/Object."<init>":()V #2 = Fieldref #4.#43 // Demo.id:Ljava/lang/Long; #3 = Fieldref #4.#44 // Demo.username:Ljava/lang/String; #4 = Class #45 // Demo #5 = Methodref #46.#47 // java/util/Objects.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z #6 = Class #48 // java/lang/Object #7 = Methodref #46.#49 // java/util/Objects.hash:([Ljava/lang/Object;)I #8 = Class #50 // java/lang/StringBuilder #9 = String #51 // { #10 = Methodref #8.#52 // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V #11 = String #53 // \"id\": #12 = Methodref #8.#54 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #13 = Methodref #8.#55 // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; #14 = String #56 // ,\"username\":\" #15 = Methodref #8.#57 // java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder; #16 = Methodref #8.#58 // java/lang/StringBuilder.toString:()Ljava/lang/String; #17 = Utf8 id #18 = Utf8 Ljava/lang/Long; #19 = Utf8 username #20 = Utf8 Ljava/lang/String; #21 = Utf8 <init> #22 = Utf8 ()V #23 = Utf8 Code #24 = Utf8 LineNumberTable #25 = Utf8 getId #26 = Utf8 ()Ljava/lang/Long; #27 = Utf8 setId #28 = Utf8 (Ljava/lang/Long;)V #29 = Utf8 getUsername #30 = Utf8 ()Ljava/lang/String; #31 = Utf8 setUsername #32 = Utf8 (Ljava/lang/String;)V #33 = Utf8 equals #34 = Utf8 (Ljava/lang/Object;)Z #35 = Utf8 StackMapTable #36 = Class #45 // Demo #37 = Utf8 hashCode #38 = Utf8 ()I #39 = Utf8 toString #40 = Utf8 SourceFile #41 = Utf8 Demo.java #42 = NameAndType #21:#22 // "<init>":()V #43 = NameAndType #17:#18 // id:Ljava/lang/Long; #44 = NameAndType #19:#20 // username:Ljava/lang/String; #45 = Utf8 Demo #46 = Class #59 // java/util/Objects #47 = NameAndType #33:#60 // equals:(Ljava/lang/Object;Ljava/lang/Object;)Z #48 = Utf8 java/lang/Object #49 = NameAndType #61:#62 // hash:([Ljava/lang/Object;)I #50 = Utf8 java/lang/StringBuilder #51 = Utf8 { #52 = NameAndType #21:#32 // "<init>":(Ljava/lang/String;)V #53 = Utf8 \"id\": #54 = NameAndType #63:#64 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #55 = NameAndType #63:#65 // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; #56 = Utf8 ,\"username\":\" #57 = NameAndType #63:#66 // append:(C)Ljava/lang/StringBuilder; #58 = NameAndType #39:#30 // toString:()Ljava/lang/String; #59 = Utf8 java/util/Objects #60 = Utf8 (Ljava/lang/Object;Ljava/lang/Object;)Z #61 = Utf8 hash #62 = Utf8 ([Ljava/lang/Object;)I #63 = Utf8 append #64 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #65 = Utf8 (Ljava/lang/Object;)Ljava/lang/StringBuilder; #66 = Utf8 (C)Ljava/lang/StringBuilder; { public Demo(); 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 3: 0 public java.lang.Long getId(); descriptor: ()Ljava/lang/Long; flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #2 // Field id:Ljava/lang/Long; 4: areturn LineNumberTable: line 10: 0 public void setId(java.lang.Long); descriptor: (Ljava/lang/Long;)V flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #2 // Field id:Ljava/lang/Long; 5: return LineNumberTable: line 14: 0 line 15: 5 public java.lang.String getUsername(); descriptor: ()Ljava/lang/String; flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #3 // Field username:Ljava/lang/String; 4: areturn LineNumberTable: line 18: 0 public void setUsername(java.lang.String); descriptor: (Ljava/lang/String;)V flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #3 // Field username:Ljava/lang/String; 5: return LineNumberTable: line 22: 0 line 23: 5 public boolean equals(java.lang.Object); descriptor: (Ljava/lang/Object;)Z flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=2 0: aload_0 1: aload_1 2: if_acmpne 7 5: iconst_1 6: ireturn 7: aload_1 8: instanceof #4 // class Demo 11: ifne 16 14: iconst_0 15: ireturn 16: aload_1 17: checkcast #4 // class Demo 20: astore_2 21: aload_0 22: getfield #2 // Field id:Ljava/lang/Long; 25: aload_2 26: getfield #2 // Field id:Ljava/lang/Long; 29: invokestatic #5 // Method java/util/Objects.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z 32: ifeq 53 35: aload_0 36: getfield #3 // Field username:Ljava/lang/String; 39: aload_2 40: getfield #3 // Field username:Ljava/lang/String; 43: invokestatic #5 // Method java/util/Objects.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z 46: ifeq 53 49: iconst_1 50: goto 54 53: iconst_0 54: ireturn LineNumberTable: line 27: 0 line 28: 5 line 30: 7 line 31: 14 line 33: 16 line 34: 21 StackMapTable: number_of_entries = 4 frame_type = 7 /* same */ frame_type = 8 /* same */ frame_type = 252 /* append */ offset_delta = 36 locals = [ class Demo ] frame_type = 64 /* same_locals_1_stack_item */ stack = [ int ] public int hashCode(); descriptor: ()I flags: ACC_PUBLIC Code: stack=4, locals=1, args_size=1 0: iconst_2 1: anewarray #6 // class java/lang/Object 4: dup 5: iconst_0 6: aload_0 7: getfield #2 // Field id:Ljava/lang/Long; 10: aastore 11: dup 12: iconst_1 13: aload_0 14: getfield #3 // Field username:Ljava/lang/String; 17: aastore 18: invokestatic #7 // Method java/util/Objects.hash:([Ljava/lang/Object;)I 21: ireturn LineNumberTable: line 39: 0 public java.lang.String toString(); descriptor: ()Ljava/lang/String; flags: ACC_PUBLIC Code: stack=3, locals=2, args_size=1 0: new #8 // class java/lang/StringBuilder 3: dup 4: ldc #9 // String { 6: invokespecial #10 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 9: astore_1 10: aload_1 11: ldc #11 // String \"id\": 13: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 16: aload_0 17: getfield #2 // Field id:Ljava/lang/Long; 20: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 23: pop 24: aload_1 25: ldc #14 // String ,\"username\":\" 27: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 30: aload_0 31: getfield #3 // Field username:Ljava/lang/String; 34: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 37: bipush 34 39: invokevirtual #15 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder; 42: pop 43: aload_1 44: bipush 125 46: invokevirtual #15 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder; 49: pop 50: aload_1 51: invokevirtual #16 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 54: areturn LineNumberTable: line 44: 0 line 45: 10 line 46: 24 line 47: 43 line 48: 50 } SourceFile: "Demo.java" ~~~ 解析: 1. 版本号 major version: 49 //java版本 jdk1.6显示的是50, jdk1.5显示的是49, 高版本能执行低版本的class文件 2. 常量池Constant pool *   Method:方法 *   Field:字段 *   String:字符串 *   Asciz:签名如`<init>`由jvm调用,其他是不能够去调用它的 *   NameAndType:变量名的类型 *   Class:类   通过字节码,我们可以看到Demo类 继承于java.lang.Object,如果类中没有显式声明构造函数的话,编译器会插入一个缺省无参的构造函数(构造函数在JVM级别是显示成`<init>`的普通函数)。 **检测代码的效率问题** 学习Java的过程中,都会了解到字符串合并时要用到StringBuffer 来代替String,那下面就来通过Java字节码来验证两种方式的效率性。 例子:一个Java类 TestString.java ~~~ public class TestString { public String addString(String str1, String str2) { return str1 + str2; } public String testStringBuffer(StringBuffer s1, String s2) { return s1.append(s2).toString(); } } ~~~ `javap –c TestString` 后字节码信息: ~~~ ➜ javac javap -verbose TestString Classfile /Users/jdxia/Desktop/javac/TestString.class Last modified 2019-11-23; size 688 bytes MD5 checksum a2dcb8bbc5d6b9f2201bfac2ac1ca684 Compiled from "TestString.java" public class TestString minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #9.#20 // java/lang/Object."<init>":()V #2 = Class #21 // java/lang/StringBuilder #3 = Methodref #2.#20 // java/lang/StringBuilder."<init>":()V #4 = Methodref #2.#22 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #5 = Methodref #2.#23 // java/lang/StringBuilder.toString:()Ljava/lang/String; #6 = Methodref #24.#25 // java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; #7 = Methodref #24.#23 // java/lang/StringBuffer.toString:()Ljava/lang/String; #8 = Class #26 // TestString #9 = Class #27 // java/lang/Object #10 = Utf8 <init> #11 = Utf8 ()V #12 = Utf8 Code #13 = Utf8 LineNumberTable #14 = Utf8 addString #15 = Utf8 (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; #16 = Utf8 testStringBuffer #17 = Utf8 (Ljava/lang/StringBuffer;Ljava/lang/String;)Ljava/lang/String; #18 = Utf8 SourceFile #19 = Utf8 TestString.java #20 = NameAndType #10:#11 // "<init>":()V #21 = Utf8 java/lang/StringBuilder #22 = NameAndType #28:#29 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #23 = NameAndType #30:#31 // toString:()Ljava/lang/String; #24 = Class #32 // java/lang/StringBuffer #25 = NameAndType #28:#33 // append:(Ljava/lang/String;)Ljava/lang/StringBuffer; #26 = Utf8 TestString #27 = Utf8 java/lang/Object #28 = Utf8 append #29 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #30 = Utf8 toString #31 = Utf8 ()Ljava/lang/String; #32 = Utf8 java/lang/StringBuffer #33 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuffer; { public TestString(); 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 1: 0 public java.lang.String addString(java.lang.String, java.lang.String); descriptor: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3 0: new #2 // class java/lang/StringBuilder 3: dup 4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V 7: aload_1 8: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 11: aload_2 12: invokevirtual #4 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: invokevirtual #5 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 18: areturn LineNumberTable: line 4: 0 public java.lang.String testStringBuffer(java.lang.StringBuffer, java.lang.String); descriptor: (Ljava/lang/StringBuffer;Ljava/lang/String;)Ljava/lang/String; flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3 0: aload_1 1: aload_2 2: invokevirtual #6 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 5: invokevirtual #7 // Method java/lang/StringBuffer.toString:()Ljava/lang/String; 8: areturn LineNumberTable: line 8: 0 } SourceFile: "TestString.java" ~~~ 我们从`java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;` 可以看出来其实对于String字符串合并,内部还是转化为StringBuilder的方法调用,这是因为String是长度不可变的,所以不如直接采用StringBuilder(与StringBuffer 长度都是可变的,只不过前者是非线程安全,后者是线程安全)进行字符串合并。 # idea中使用javap ![](https://img.kancloud.cn/d3/c7/d3c7a955bd44456543173e27a595c68b_1882x778.png) Name是在类中,右键时使用时的名称 ![](https://img.kancloud.cn/2d/af/2dafd6b0f35c0bd83d0018522bd4081e_2192x1378.png) # idea中使用jclasslib 安装jclasslib插件 显示jclasslib工具 ![](https://img.kancloud.cn/79/d5/79d5699718ce45199c3bf4cea03b1759_271x147.png) ![](https://img.kancloud.cn/65/7c/657cf5b6dfd673d69b012cdddb3c3eb2_695x410.png)