用描述符描述方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序放在一组()之内,如方法:String getRealnameByIdAndNickname(int id,String name)的描述符为:(I,Ljava/lang/String;)Ljava/lang/String;
Java是一个单继承,多实现的语言。
访问标志(Access_Flag)0x0002 private
字段表集合(field_info)字段表结构:
方法表集合(method_info) 方法表结构: 方法表结构实例: code结构(code attribute):每一个方法的结构内容code_length : 之后的字节 会转换成 助记符
附加属性LineNumberTable : 源代码和行号的对应关系。方便抛异常时,定义出错的位置。
在字节码文件中。 this 属性是默认当做第一个参数给传入进去的。
字节码查看工具 的GitHub地址
idea也有插件。 jclasslib
字节码反编译练习 // 编译下边的文件,然后反编译。对应字节码去翻译一遍,学习 字节码结构。 // 整体的复习。 public class MyTest2{ String str = "welcome"; private int x = 5; public static Integer in = 10; public static void main(String[] args){ MyTest2 myTest2 = new MyTest2(); myTest2.setX(8); in = 20; } public void setX(int x){ this.x = x ; } } -- 反编译文件内容为: ➜ jdk8 javap -verbose build.classes.java.main.com.erwa.bytecode.MyTest2 (此时的命令时不打印私有的信息的。需要加上一个 -p 的参数) 警告: 二进制文件build.classes.java.main.com.erwa.bytecode.MyTest2包含com.erwa.bytecode.MyTest2 Classfile /Users/erwa/Desktop/work/workspace/idea/jdk8/build/classes/java/main/com/erwa/bytecode/MyTest2.class Last modified 2020-2-13; size 833 bytes MD5 checksum c119f2eae8cb307e9b90f835d460a4ad Compiled from "MyTest2.java" public class com.erwa.bytecode.MyTest2 minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #10.#34 // java/lang/Object."<init>":()V #2 = String #35 // welcome #3 = Fieldref #5.#36 // com/erwa/bytecode/MyTest2.str:Ljava/lang/String; #4 = Fieldref #5.#37 // com/erwa/bytecode/MyTest2.x:I #5 = Class #38 // com/erwa/bytecode/MyTest2 #6 = Methodref #5.#34 // com/erwa/bytecode/MyTest2."<init>":()V #7 = Methodref #5.#39 // com/erwa/bytecode/MyTest2.setX:(I)V #8 = Methodref #40.#41 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #9 = Fieldref #5.#42 // com/erwa/bytecode/MyTest2.in:Ljava/lang/Integer; #10 = Class #43 // java/lang/Object #11 = Utf8 str #12 = Utf8 Ljava/lang/String; #13 = Utf8 x #14 = Utf8 I #15 = Utf8 in #16 = Utf8 Ljava/lang/Integer; #17 = Utf8 <init> #18 = Utf8 ()V #19 = Utf8 Code #20 = Utf8 LineNumberTable #21 = Utf8 LocalVariableTable #22 = Utf8 this #23 = Utf8 Lcom/erwa/bytecode/MyTest2; #24 = Utf8 main #25 = Utf8 ([Ljava/lang/String;)V #26 = Utf8 args #27 = Utf8 [Ljava/lang/String; #28 = Utf8 myTest2 #29 = Utf8 setX #30 = Utf8 (I)V #31 = Utf8 <clinit> #32 = Utf8 SourceFile #33 = Utf8 MyTest2.java #34 = NameAndType #17:#18 // "<init>":()V #35 = Utf8 welcome #36 = NameAndType #11:#12 // str:Ljava/lang/String; #37 = NameAndType #13:#14 // x:I #38 = Utf8 com/erwa/bytecode/MyTest2 #39 = NameAndType #29:#30 // setX:(I)V #40 = Class #44 // java/lang/Integer #41 = NameAndType #45:#46 // valueOf:(I)Ljava/lang/Integer; #42 = NameAndType #15:#16 // in:Ljava/lang/Integer; #43 = Utf8 java/lang/Object #44 = Utf8 java/lang/Integer #45 = Utf8 valueOf #46 = Utf8 (I)Ljava/lang/Integer; { java.lang.String str; descriptor: Ljava/lang/String; flags: public static java.lang.Integer in; descriptor: Ljava/lang/Integer; flags: ACC_PUBLIC, ACC_STATIC public com.erwa.bytecode.MyTest2(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #2 // String welcome 7: putfield #3 // Field str:Ljava/lang/String; 10: aload_0 11: iconst_5 12: putfield #4 // Field x:I 15: return LineNumberTable: line 3: 0 line 4: 4 line 5: 10 LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lcom/erwa/bytecode/MyTest2; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #5 // class com/erwa/bytecode/MyTest2 3: dup 4: invokespecial #6 // Method "<init>":()V 7: astore_1 8: aload_1 9: bipush 8 11: invokevirtual #7 // Method setX:(I)V 14: bipush 20 16: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 19: putstatic #9 // Field in:Ljava/lang/Integer; 22: return LineNumberTable: line 8: 0 line 9: 8 line 10: 14 line 11: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [Ljava/lang/String; 8 15 1 myTest2 Lcom/erwa/bytecode/MyTest2; public void setX(int); descriptor: (I)V flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: iload_1 2: putfield #4 // Field x:I 5: return LineNumberTable: line 13: 0 line 14: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/erwa/bytecode/MyTest2; 0 6 1 x I static {}; descriptor: ()V flags: ACC_STATIC Code: stack=1, locals=0, args_size=0 0: bipush 10 2: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 5: putstatic #9 // Field in:Ljava/lang/Integer; 8: return LineNumberTable: line 6: 0 } SourceFile: "MyTest2.java" 加上synchronized关键字字节码为什么除了访问权限多了synchronized之外,其他的地方都一样。
因为synchronized使用的方式有多种:
如果synchronized用在实例方法上,表示对此方法加了一个锁。
如果用在了对象上,则字节码会生成锁的入口和出口。
synchronized用在类中的静态方法上, 其实是给当前的类的对象上的锁。
关于锁:能不用synchronized就不用。使用轻量级的 lock 。
构造方法和静态代码块字节码如果没有设置构造方法,会默认生成一个无参构造。如果有静态方法,会初始化一个clinit的方法。
全局变量是在构造方法初始化的时候完成赋值的。
一个构造方法对应一个init方法。(全局变量的赋值,会在每个init方法中都重新执行一次)