反编译详解Java枚举类Enum

本文详细分析了Java枚举类的创建、字节码指令及运行过程。通过探讨`getCode()`和`setCode()`方法的字节码,解释了方法调用和成员变量赋值的操作。同时,枚举常量如何通过构造函数给成员变量赋值的过程也得到了清晰的阐述,揭示了枚举类在JVM中的内部实现细节。
摘要由CSDN通过智能技术生成

从字节码指令分析Java枚举类的运行过程。

目录

一、创建的枚举类

二、反编译字节码

1)getCode()方法分析

2)setCode()方法分析

三、枚举常量给枚举类成员变量赋值过程分析


一、创建的枚举类

public enum ResponseCodeEnum {
    SUCCESS("0000", "success"),
    BUSINESS_EXCEPTION("5000", "wrong");

    private String code;
    private String message;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    ResponseCodeEnum(String code, String message) {
        this.code = code;
        this.message = message;
    }
}

二、反编译字节码

1)getCode()方法分析

字节码各指令含义在这里不再阐述,主要讲一下字节码运行之后会产生什么效果。

了解过JVM内存模型的都知道,JVM中每一个方法都会存在一个方法栈。而字节码执行中,就会存在一个操作数栈,一个局部表量表,对应图片中stack就是操作数栈,局部变量可以在LocalVariableTable中看到;其中,Slot就是字节码中操作的一个下标。

在大概了解了执行中存在哪些资源后,就可以开始分析了。

首先public java.lang.String getCode()就是定义的方法声明,下面的descriptor也是描述方法的;()表示这个方法,并且没有参数,Ljava/lang/String,其中L表示这个一个引用类,后面表示这个引用类是什么类型,意思就是这个方法有返回值,返回值类型为字符串类型。

从Code:下面开始依次分析每一行字节码含义。

这里的stack表示操作栈的深度,为1,locals是局部变量表的变量个数,args_size表示参数个数,这里getCode()没有参数,但是显示为1,是因为每个实例方法都会有一个隐藏参数this。

aload_0表示将Slot0这个变量压入操作栈栈顶,即将this压入栈

getfield很好理解,就是获取this对应的code的这个变量的值,并且会把此时位于栈顶的this弹出栈。

areturn就是返回了。局部变量表和栈都会清零。

2)setCode()方法分析

和getCode()相同的地方就不再阐述,这里说一下descriptor,(Ljava/lang/String;)表示这个方法有一个参数,参数为String类型,V表示该方法没有返回值,为Void

aload_0,将这个对象this压入栈

aload_1,将code这个参数的值压入栈,此时,code在栈顶

putfield,将栈顶的code的值赋值给栈顶下一个this对象对应的属性,此时,this的code成员属性的值就是参数code的值了

return。局部变量表和栈都会清零。

三、枚举常量给枚举类成员变量赋值过程分析

通过上面getCode()和setCode(),可以大致熟悉一下字节码指令做的事了,下面就分析,枚举常量是如何通过构造函数给枚举类成员变量赋值的。

所有的枚举类都继承自Enum这个公共基类,在这个公共基类中,有一个构造方法,如下:

Enum(String name, int ordinal),其中name就是我们平常写在枚举类中的常量,在这个例子中就是SUCCESS和FAIL,ordinal则是枚举常量的顺序,这里SUCCESS就是0,FAIL就是1。

构造函数字节码如下:

构造函数也比较简单,主要就是前面4行,前面4行就是在执行公共基类的构造函数。aload_0和aload_1会在后面讲到。

第三行invokespecial执行的方法,通过注释可以看到那个方法是没有返回值的,参数是String和int,和公共基类的方法一致。

接下来就是枚举常量的执行字节码:

new,运行构造函数,创建一个枚举类实例,并压入栈顶

dup,复制栈顶数据,并压入栈,此时操作数栈有两个值,都是new的实例

ldc,从常量池中取出SUCCESS并压入栈

iconst_0,将基本类型int的0压入栈

ldc,从常量池中取出SUCCESS中的code的值(这里是0000)并压入栈

ldc,从常量池中取出SUCCESS中的success的值(这里是success)并压入栈

invokespecial,执行构造函数,这里通过注释,可以分析出这个方法是 method(String, int, String, String),公共基类Enum的构造函数和自定义的枚举类的构造函数的合并。

putstatic,为枚举类的SUCCESS常量赋值。

一个枚举类大致就会经历这几个过程,从字节码我们可以看到,枚举类的常量都是static的,虽然我们没有显示的指定。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值