一、创建测试类
package com.example.jvm.bytecode; 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; } }
反编译MyTest2.class文件
D:workspacestudy jvm_demouildclassesjavamaincomexamplejvmytecode>javap -verbose MyTest2.class Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest2.class Last modified 2019-6-26; size 847 bytes MD5 checksum d8f82e3e7255d9a738591c52d3a5417b Compiled from "MyTest2.java" public class com.example.jvm.bytecode.MyTest2 SourceFile: "MyTest2.java" minor version: 0 major version: 51 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/example/jvm/bytecode/MyTest2.str:Ljava/lang/String; #4 = Fieldref #5.#37 // com/example/jvm/bytecode/MyTest2.x:I #5 = Class #38 // com/example/jvm/bytecode/MyTest2 #6 = Methodref #5.#34 // com/example/jvm/bytecode/MyTest2."<init>":()V #7 = Methodref #5.#39 // com/example/jvm/bytecode/MyTest2.setX:(I)V #8 = Methodref #40.#41 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #9 = Fieldref #5.#42 // com/example/jvm/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/example/jvm/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/example/jvm/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; flags: public static java.lang.Integer in; flags: ACC_PUBLIC, ACC_STATIC public com.example.jvm.bytecode.MyTest2(); 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 5: 4 line 7: 10 LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lcom/example/jvm/bytecode/MyTest2; public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #5 // class com/example/jvm/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 12: 0 line 14: 8 line 16: 14 line 17: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [Ljava/lang/String; 8 15 1 myTest2 Lcom/example/jvm/bytecode/MyTest2; public void setX(int); 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 20: 0 line 21: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/example/jvm/bytecode/MyTest2; 0 6 1 x I static {}; 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 9: 0 }
二、将setX改为private
此时需要使用javap -verbose -p MyTest2.class才能显示私有方法
D:workspacestudy jvm_demouildclassesjavamaincomexamplejvmytecode>javap -verbose -p MyTest2.class Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest2.class Last modified 2019-6-27; size 847 bytes MD5 checksum f9ed848bb768588b932c395b40c509a8 Compiled from "MyTest2.java" public class com.example.jvm.bytecode.MyTest2 SourceFile: "MyTest2.java" minor version: 0 major version: 51 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/example/jvm/bytecode/MyTest2.str:Ljava/lang/String; #4 = Fieldref #5.#37 // com/example/jvm/bytecode/MyTest2.x:I #5 = Class #38 // com/example/jvm/bytecode/MyTest2 #6 = Methodref #5.#34 // com/example/jvm/bytecode/MyTest2."<init>":()V #7 = Methodref #5.#39 // com/example/jvm/bytecode/MyTest2.setX:(I)V #8 = Methodref #40.#41 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #9 = Fieldref #5.#42 // com/example/jvm/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/example/jvm/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/example/jvm/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; flags: private int x; flags: ACC_PRIVATE public static java.lang.Integer in; flags: ACC_PUBLIC, ACC_STATIC public com.example.jvm.bytecode.MyTest2(); 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 5: 4 line 7: 10 LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lcom/example/jvm/bytecode/MyTest2; public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #5 // class com/example/jvm/bytecode/MyTest2 3: dup 4: invokespecial #6 // Method "<init>":()V 7: astore_1 8: aload_1 9: bipush 8 11: invokespecial #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 12: 0 line 14: 8 line 16: 14 line 17: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [Ljava/lang/String; 8 15 1 myTest2 Lcom/example/jvm/bytecode/MyTest2; private void setX(int); flags: ACC_PRIVATE Code: stack=2, locals=2, args_size=2 0: aload_0 1: iload_1 2: putfield #4 // Field x:I 5: return LineNumberTable: line 20: 0 line 21: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/example/jvm/bytecode/MyTest2; 0 6 1 x I static {}; 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 9: 0 }
三、现在将setX方法增加synchronized 修饰符
private synchronized void setX(int x)
反编译后无synchronized和有synchronized的区别如下图:
四、在类中增加test方法,方法里面使用了synchronize
private void test(String str){ synchronized (obj){ System.out.println("hello world"); } }
反编译后如下:
private void test(java.lang.String); flags: ACC_PRIVATE Code: stack=2, locals=4, args_size=2 0: aload_0 1: getfield #6 // Field obj:Ljava/lang/Object; 4: dup 5: astore_2 6: monitorenter 7: getstatic #12 // Field java/lang/System.out:Ljava/io/PrintStream; 10: ldc #13 // String hello world 12: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 15: aload_2 16: monitorexit 17: goto 25 20: astore_3 21: aload_2 22: monitorexit 23: aload_3 24: athrow 25: return Exception table: from to target type 7 17 20 any 20 23 20 any LineNumberTable: line 26: 0 line 27: 7 line 28: 15 line 29: 25 LocalVariableTable: Start Length Slot Name Signature 0 26 0 this Lcom/example/jvm/bytecode/MyTest2; 0 26 1 str Ljava/lang/String; StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 20 locals = [ class com/example/jvm/bytecode/MyTest2, class java/lang/String, class java/lang/Object ] stack = [ class java/lang/Throwable ] frame_type = 250 /* chop */ offset_delta = 4
出现了6: monitorenter和22: monitorexit
给当前MyTest2类所对应的class对象上锁
private synchronized static void test2(){
}
给当前对象上锁
private synchronized void setX(int x){
this.x = x;
}
五、字节码文件分析
最终需要分析的java文件
package com.example.jvm.bytecode; 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; } private synchronized void setX(int x){ this.x = x; } private void test(String str){ synchronized (str){ System.out.println("hello world"); } } private synchronized static void test2(){ } }
然后反编译MyTest2.class
Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest2.class Last modified 2019-6-27; size 1265 bytes MD5 checksum 1ca3fedabb74af431cc850f3f87b7763 Compiled from "MyTest2.java" public class com.example.jvm.bytecode.MyTest2 SourceFile: "MyTest2.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #13.#45 // java/lang/Object."<init>":()V #2 = String #46 // Welcome #3 = Fieldref #5.#47 // com/example/jvm/bytecode/MyTest2.str:Ljava/lang/String; #4 = Fieldref #5.#48 // com/example/jvm/bytecode/MyTest2.x:I #5 = Class #49 // com/example/jvm/bytecode/MyTest2 #6 = Methodref #5.#45 // com/example/jvm/bytecode/MyTest2."<init>":()V #7 = Methodref #5.#50 // com/example/jvm/bytecode/MyTest2.setX:(I)V #8 = Methodref #51.#52 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #9 = Fieldref #5.#53 // com/example/jvm/bytecode/MyTest2.in:Ljava/lang/Integer; #10 = Fieldref #54.#55 // java/lang/System.out:Ljava/io/PrintStream; #11 = String #56 // hello world #12 = Methodref #57.#58 // java/io/PrintStream.println:(Ljava/lang/String;)V #13 = Class #59 // java/lang/Object #14 = Utf8 str #15 = Utf8 Ljava/lang/String; #16 = Utf8 x #17 = Utf8 I #18 = Utf8 in #19 = Utf8 Ljava/lang/Integer; #20 = Utf8 <init> #21 = Utf8 ()V #22 = Utf8 Code #23 = Utf8 LineNumberTable #24 = Utf8 LocalVariableTable #25 = Utf8 this #26 = Utf8 Lcom/example/jvm/bytecode/MyTest2; #27 = Utf8 main #28 = Utf8 ([Ljava/lang/String;)V #29 = Utf8 args #30 = Utf8 [Ljava/lang/String; #31 = Utf8 myTest2 #32 = Utf8 setX #33 = Utf8 (I)V #34 = Utf8 test #35 = Utf8 (Ljava/lang/String;)V #36 = Utf8 StackMapTable #37 = Class #49 // com/example/jvm/bytecode/MyTest2 #38 = Class #60 // java/lang/String #39 = Class #59 // java/lang/Object #40 = Class #61 // java/lang/Throwable #41 = Utf8 test2 #42 = Utf8 <clinit> #43 = Utf8 SourceFile #44 = Utf8 MyTest2.java #45 = NameAndType #20:#21 // "<init>":()V #46 = Utf8 Welcome #47 = NameAndType #14:#15 // str:Ljava/lang/String; #48 = NameAndType #16:#17 // x:I #49 = Utf8 com/example/jvm/bytecode/MyTest2 #50 = NameAndType #32:#33 // setX:(I)V #51 = Class #62 // java/lang/Integer #52 = NameAndType #63:#64 // valueOf:(I)Ljava/lang/Integer; #53 = NameAndType #18:#19 // in:Ljava/lang/Integer; #54 = Class #65 // java/lang/System #55 = NameAndType #66:#67 // out:Ljava/io/PrintStream; #56 = Utf8 hello world #57 = Class #68 // java/io/PrintStream #58 = NameAndType #69:#35 // println:(Ljava/lang/String;)V #59 = Utf8 java/lang/Object #60 = Utf8 java/lang/String #61 = Utf8 java/lang/Throwable #62 = Utf8 java/lang/Integer #63 = Utf8 valueOf #64 = Utf8 (I)Ljava/lang/Integer; #65 = Utf8 java/lang/System #66 = Utf8 out #67 = Utf8 Ljava/io/PrintStream; #68 = Utf8 java/io/PrintStream #69 = Utf8 println { java.lang.String str; flags: private int x; flags: ACC_PRIVATE public static java.lang.Integer in; flags: ACC_PUBLIC, ACC_STATIC public com.example.jvm.bytecode.MyTest2(); 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 5: 4 line 7: 10 LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lcom/example/jvm/bytecode/MyTest2; public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #5 // class com/example/jvm/bytecode/MyTest2 3: dup 4: invokespecial #6 // Method "<init>":()V 7: astore_1 8: aload_1 9: bipush 8 11: invokespecial #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 12: 0 line 14: 8 line 16: 14 line 17: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [Ljava/lang/String; 8 15 1 myTest2 Lcom/example/jvm/bytecode/MyTest2; private synchronized void setX(int); flags: ACC_PRIVATE, ACC_SYNCHRONIZED Code: stack=2, locals=2, args_size=2 0: aload_0 1: iload_1 2: putfield #4 // Field x:I 5: return LineNumberTable: line 20: 0 line 21: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/example/jvm/bytecode/MyTest2; 0 6 1 x I private void test(java.lang.String); flags: ACC_PRIVATE Code: stack=2, locals=4, args_size=2 0: aload_1 1: dup 2: astore_2 3: monitorenter 4: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream; 7: ldc #11 // String hello world 9: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 12: aload_2 13: monitorexit 14: goto 22 17: astore_3 18: aload_2 19: monitorexit 20: aload_3 21: athrow 22: return Exception table: from to target type 4 14 17 any 17 20 17 any LineNumberTable: line 24: 0 line 25: 4 line 26: 12 line 27: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 this Lcom/example/jvm/bytecode/MyTest2; 0 23 1 str Ljava/lang/String; StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 17 locals = [ class com/example/jvm/bytecode/MyTest2, class java/lang/String, class java/lang/Object ] stack = [ class java/lang/Throwable ] frame_type = 250 /* chop */ offset_delta = 4 private static synchronized void test2(); flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNCHRONIZED Code: stack=0, locals=0, args_size=0 0: return LineNumberTable: line 31: 0 static {}; 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 9: 0 }
然后打开WinHex打开MyTest2.class 文件