Enum枚举

本文详细介绍了Java中枚举的实现原理,包括编译过程中的类生成、枚举常量的表示以及values()和valueOf()等方法。枚举可以添加方法、变量和构造函数,实现抽象方法,甚至可以实现接口。此外,枚举在单例模式和序列化中的应用也得到了讨论,枚举确保了单例的唯一性和序列化的安全性。
摘要由CSDN通过智能技术生成

枚举实现的原理1

  • 使用enum定义的枚举类型,在编译过程中,编译器会生成一个与enum类同名的普通类,该类继承java.lang.Enum抽象类,且该类的类型为final,无法被继承。
    ^f70295
  • 枚举类型中的枚举常量,在编译过程中,编译器会在与枚举类型同名的普通类中,定义同名的静态实例对象。定义方式为public static final Day MONDAY。其中MONDAY就是枚举类型中定义的枚举常量。
  • 编译会在与枚举类同名的普通类中插入两个静态方法values()valueOf()

枚举常用的方法2

  • ordinal() 返回枚举常量的序数,枚举常量在枚举声明中的位置,其中初始常量序数为零

  • values() 获取枚举中的所有枚举常量,并作为数组返回

  • valueOf() 根据名称来获取枚举常量

  • getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象

  • getEnumConstants() 返回该枚举类型的所有元素,如果Class对象不是枚举类型,则返回null

    Class clasz=day.getDeclaringClass();
    Day[] days=(Day[])clasz.getEnumConstants();
    System.out.println(Arrays.toString(days));
    

枚举的进阶用法

使用关键字enum定义的枚举类,除了不能使用继承(因为编译器会自动为我们继承Enum抽象类而Java只支持单继承,因此枚举类是无法手动实现继承的),可以把enum类当成常规类,也就是说我们可以向enum类中添加方法和变量,甚至是main方法。 ^48226b

  • 可以向枚举中添加方法,添加变量,自定义构造方法。可以用于向枚举常量添加说明性文字。枚举常量定义结束后,记住要用分号结束。

    enum Day {
        MONDAY("星期一");
    
        // 枚举中定义变量
        private String desc;
    
        // 枚举中自定义构造函数
        private Day(String desc)   {
            this.desc=desc;
        }
    
        // 覆盖父类方法
        public String toString() {
            return desc;
        }
    
        // 枚举类中运行main方法
        public static void main(String[] args) {
            Day day = Day.MONDAY;
            System.out.println(day);
        }
    }
    
  • 覆盖enum类方法。只有toString() 方法没有final修饰,只能覆盖toString()方法

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

    enum Day {
        FIRST {
            @Override
            public String getInfo() {
                return "FIRST TIME";
            }
        },
        SECOND {
            @Override
            public String getInfo() {
                return "SECOND TIME";
            }
        };
        // 枚举类中定义抽象方法
        abstract public  String getInfo() ;
        public static void main(String[] args) {
            Day day = Day.FIRST;
            System.out.println(day.getInfo());
        }
    }
    
  • enum不可以继承,但是可以实现多个接口

    public enum Meal {
        APPETIZER(Food.Appetizer.class), 
        MainCourse(Food.Appetizer.class);
    
        // 继承Food接口的枚举类的所有枚举常量
        private Food[] values;
        // 自定义构造函数
        private Meal(Class<? extends Food> kind) {
            // 获取枚举类的所有枚举常量
            values = kind.getEnumConstants();
        }
    
        public void show() {
            System.out.println(Arrays.toString(values));
        }
    
        public static void main(String[] args) {
            Meal appetizer = Meal.APPETIZER;
            appetizer.show();
        }
    
        public interface Food {
            // 枚举类型实现接口
            enum Appetizer implements Food {
                SALAD, SOUP, SPRINT_ROLLS;
            }
    
            enum MainCourse implements Food {
                LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO;
            }
        }
    }
    

枚举与Switch

枚举与单例

序列化可能会破坏单例模式,比较每次反序列化一个序列化的对象实例时都会创建一个新的实例。使用枚举类能够比较简洁地完成这个问题。

我们也可以像常规类一样编写enum类,为其添加变量和方法,访问方式也更简单,使用SingletonEnum.INSTANCE进行访问,这样也就避免调用getInstance()方法,更重要的是使用枚举单例的写法,我们完全不用考虑序列化和反射的问题。枚举序列化是由JVM保证的,每一个枚举类型和定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定:在序列化时Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.EnumvalueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的并禁用了writeObjectreadObjectreadObjectNoDatawriteReplacereadResolve等方法,从而保证了枚举实例的唯一性

public enum  SingletonEnum {
    INSTANCE;
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
}

参考资料


  1. 深入理解JavaEnum类型 ↩︎

  2. 深入理解Java Enum 类型 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值