Java 枚举Enum理解

1.楔子

枚举能继承别枚举吗?枚举能继承其他类吗?枚举能实现接口吗?枚举能被其他类继承吗?
本文就是要探讨这些问题。

2. 准备

本文需要使用到反编译,请自行安装Jad(JAva Decompiler)反编译工具。由于该工具最新的版本也只支持Java 4,不支持Java 5,所以能够很好的保留jdk5之后的例如枚举等原生的编译结果。

jad的使用教程:Java反编译工具Jad详解

JD-GUI反编译工具支持枚举,更高级,更强大,所以反编译的结果与源码基本一致,所以反编译是看不到JAVA编译的处理结果。

3. 枚举反编译

枚举源代码如下:

public enum ErrorCode {
    SUCCESS(1);

    private int code;

    ErrorCode(int code) {
        this.code = code;
    }
}

执行jad -sjava ErrorCode.class (指定生成源代码的后缀名:-sjava)。
反编译结果:

package com.sino.daily.code_2019_4_24;


public final class ErrorCode extends Enum
{
    //编译器为我们添加的静态的values()方法
    public static ErrorCode[] values()
    {
        return (ErrorCode[])$VALUES.clone();
    }
	//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
    public static ErrorCode valueOf(String name)
    {
        return (ErrorCode)Enum.valueOf(com/sino/daily/code_2019_4_24/ErrorCode, name);
    }

   //私有构造函数,被改写,加入了s-name和i-ordinal
    private ErrorCode(String s, int i, int code)
    {
        super(s, i);
        this.code = code;
    }

   // 前面定义的枚举实例
    public static final ErrorCode SUCCESS;
    private int code;
    private static final ErrorCode $VALUES[];
    
   //实例化枚举实例
    static 
    {
        SUCCESS = new ErrorCode("SUCCESS", 0, 1);
        // 获取到所有的枚举实例对象最为values
        $VALUES = (new ErrorCode[] {
            SUCCESS
        });
    }
}
  • public final class ErrorCode extends Enum 看出该类是继承自java.lang.Enum类(该类是一个抽象类public abstract class Enum<E extends Enum<E>>), 故不能再继承其他类,而且类时final的,所以也不能被其他类继承。
  • 编译器为我们生成了ErrorCode类的对象public static final ErrorCode SUCCESS作为枚举实例,并进行初始化SUCCESS = new ErrorCode("SUCCESS", 0, 1)。初始化时额外增加了两个参数s-name(举常量的名称)和i-ordinal(枚举常量的序数,其中初始常量序数为零)
    在这里插入图片描述
  • 如果枚举实例的声明位置发生变化,那么ordinal方法获取到的值也随之变化,注意在大多数情况下我们都不应该首先使用该方法,毕竟它总是变幻莫测的。
  • valueOf(String name)方法的作用是根据名称获取枚举变量,采用了Enum类中的valueOf方法,调用方式为:(ErrorCode)Enum.valueOf(com/sino/daily/code_2019_4_24/ErrorCode, name), 入参是枚举类和枚举实例名,主要实现思路是采用反射,获取到所有的实例对象(调用values方法)放入MAP<实例名, 实例对象>中,然后从MAP中取。
    在这里插入图片描述

4.enum类中定义抽象方法

与常规抽象类一样,enum类允许我们为其定义抽象方法,然后使每个枚举实例都实现该方法,以便产生不同的行为方式,注意abstract关键字对于枚举类来说并不是必须的如下:

public enum Operation{
    ADD {
        @Override
        public int eval(int arg1, int arg2) { return arg1 + arg2; };
    },

    SUBTRACT {
        @Override
        public int eval(int arg1, int arg2) { return arg1 - arg2; };
    };

    //定义抽象方法
    public abstract int eval(int arg1, int arg2);

    public static void main(String[] args) {
        System.out.println(Operation.ADD.eval(1,2));
        System.out.println(Operation.SUBTRACT.eval(1,2));
    }
}

通过这种方式就可以轻而易举地定义每个枚举实例的不同行为方式。我们可能注意到,enum类的实例似乎表现出了多态的特性,但这并非真正的多态。

同样进行反编译,反编译后发现多了几个内部类。
在这里插入图片描述
Operation$1的反编译结果为:
在这里插入图片描述
每个重载了eval的枚举实例都对应了一个匿名内部类。

5. enum类与接口

由于Java单继承的原因,enum类并不能再继承其它类,但并不妨碍它实现接口,因此enum类同样是可以实现多接口的。

6.参考文献

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读