字节码解析

在java中创建三个类

分别为:

public class Emp {

// 被final修饰
    public static final int age=30;

    static {
        System.out.println("emp....");
    }
}

public class User {

    public static int age=30;

    static {
        System.out.println("user....");
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println(User.age);
        System.out.println(Emp.age);
    }
}

根据运行Test中的main方法的结果可以看到


user....
30
30

Emp中的age被final修饰后,没有打印静态代码块中的内容。
这是为什么呢?

反编译代码

通过javap命令来进行反编译代码

/ 进入idea中target中的class文件夹下,打开Termail控制台。
使用命令
javap -v User
javap -v emp

编译User.class源码后的结果

警告: 二进制文件User包含com.test.User
Classfile /Users/lida/private/project/qmtools/out/production/scala/com/test/User.class
  Last modified 2024-4-24; size 499 bytes
  MD5 checksum 1d09d609093679118c6e95baffbcedf3
  Compiled from "User.java"
public class com.test.User
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #6.#21         // com/test/User.age:I
   #3 = Fieldref           #22.#23        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = String             #24            // user....
   #5 = Methodref          #25.#26        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #6 = Class              #27            // com/test/User
   #7 = Class              #28            // java/lang/Object
   #8 = Utf8               age
   #9 = Utf8               I
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Lcom/test/User;
  #17 = Utf8               <clinit>
  #18 = Utf8               SourceFile
  #19 = Utf8               User.java
  #20 = NameAndType        #10:#11        // "<init>":()V
  #21 = NameAndType        #8:#9          // age:I
  #22 = Class              #29            // java/lang/System
  #23 = NameAndType        #30:#31        // out:Ljava/io/PrintStream;
  #24 = Utf8               user....
  #25 = Class              #32            // java/io/PrintStream
  #26 = NameAndType        #33:#34        // println:(Ljava/lang/String;)V
  #27 = Utf8               com/test/User
  #28 = Utf8               java/lang/Object
  #29 = Utf8               java/lang/System
  #30 = Utf8               out
  #31 = Utf8               Ljava/io/PrintStream;
  #32 = Utf8               java/io/PrintStream
  #33 = Utf8               println
  #34 = Utf8               (Ljava/lang/String;)V
{
  public static int age;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC

  public com.test.User();
    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/test/User;

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: bipush        30
         2: putstatic     #2                  // Field age:I
         5: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         8: ldc           #4                  // String user....
        10: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        13: return
      LineNumberTable:
        line 11: 0
        line 14: 5
        line 15: 13
}
SourceFile: "User.java"

这个里面可以清晰的看到,age是在静态代码块中进行复制的。

编译Emp.class源码后的结果

警告: 二进制文件Emp包含com.test.Emp
Classfile /Users/lida/private/project/qmtools/out/production/scala/com/test/Emp.class
  Last modified 2024-4-24; size 505 bytes
  MD5 checksum a790a625f63a08555848173ef4d808a6
  Compiled from "Emp.java"
public class com.test.Emp
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#21         // java/lang/Object."<init>":()V
   #2 = Fieldref           #22.#23        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #24            // emp....
   #4 = Methodref          #25.#26        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #27            // com/test/Emp
   #6 = Class              #28            // java/lang/Object
   #7 = Utf8               age
   #8 = Utf8               I
   #9 = Utf8               ConstantValue
  #10 = Integer            30
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lcom/test/Emp;
  #18 = Utf8               <clinit>
  #19 = Utf8               SourceFile
  #20 = Utf8               Emp.java
  #21 = NameAndType        #11:#12        // "<init>":()V
  #22 = Class              #29            // java/lang/System
  #23 = NameAndType        #30:#31        // out:Ljava/io/PrintStream;
  #24 = Utf8               emp....
  #25 = Class              #32            // java/io/PrintStream
  #26 = NameAndType        #33:#34        // println:(Ljava/lang/String;)V
  #27 = Utf8               com/test/Emp
  #28 = Utf8               java/lang/Object
  #29 = Utf8               java/lang/System
  #30 = Utf8               out
  #31 = Utf8               Ljava/io/PrintStream;
  #32 = Utf8               java/io/PrintStream
  #33 = Utf8               println
  #34 = Utf8               (Ljava/lang/String;)V
{
  public static final int age;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    ConstantValue: int 30

  public com.test.Emp();
    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/test/Emp;

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String emp....
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 14: 0
        line 15: 8
}
SourceFile: "Emp.java"

可以清楚的看到,这块是在静态代码块外面进行的赋值

编译Test.class源码后的结果

Classfile /Users/lida/private/project/qmtools/out/production/scala/com/test/Test.class
  Last modified 2024-4-24; size 569 bytes
  MD5 checksum 32ffb98839c3ba98020e9fcc8917f021
  Compiled from "Test.java"
public class com.test.Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#21         // java/lang/Object."<init>":()V
   #2 = Fieldref           #22.#23        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Fieldref           #24.#25        // com/test/User.age:I
   #4 = Methodref          #26.#27        // java/io/PrintStream.println:(I)V
   #5 = Class              #28            // com/test/Emp
   #6 = Class              #29            // com/test/Test
   #7 = Class              #30            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lcom/test/Test;
  #15 = Utf8               main
  #16 = Utf8               ([Ljava/lang/String;)V
  #17 = Utf8               args
  #18 = Utf8               [Ljava/lang/String;
  #19 = Utf8               SourceFile
  #20 = Utf8               Test.java
  #21 = NameAndType        #8:#9          // "<init>":()V
  #22 = Class              #31            // java/lang/System
  #23 = NameAndType        #32:#33        // out:Ljava/io/PrintStream;
  #24 = Class              #34            // com/test/User
  #25 = NameAndType        #35:#36        // age:I
  #26 = Class              #37            // java/io/PrintStream
  #27 = NameAndType        #38:#39        // println:(I)V
  #28 = Utf8               com/test/Emp
  #29 = Utf8               com/test/Test
  #30 = Utf8               java/lang/Object
  #31 = Utf8               java/lang/System
  #32 = Utf8               out
  #33 = Utf8               Ljava/io/PrintStream;
  #34 = Utf8               com/test/User
  #35 = Utf8               age
  #36 = Utf8               I
  #37 = Utf8               java/io/PrintStream
  #38 = Utf8               println
  #39 = Utf8               (I)V
{
  public com.test.Test();
    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/test/Test;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: getstatic     #3                  // Field com/test/User.age:I
         6: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
         9: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        12: bipush        30
        14: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
        17: return
      LineNumberTable:
        line 11: 0
        line 12: 9
        line 13: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  args   [Ljava/lang/String;
}
SourceFile: "Test.java"

结论

从Test.class的代码中就可以看到,获取User中的age时,是获取的静态代码中的数据。但是Emp中的age是常量

posted @ 2024-04-24 23:26  King-DA  阅读(12)  评论(0)    收藏  举报