关于枚举

来源:Java编程的逻辑

枚举

基本实现原理

枚举类型实际上会被Java编译器转换为一个对应的final类,这个类继承了Java API中的java.lang.Enum类。

Enum类有两个实例变量String name和int ordinal,在构造方法中需要传递,name(), toString(), ordinal(), compareTo(), equals()方法都是由Enum类根据其实例变量name和ordinal实现的。

values和valueOf方法是编译器给每个枚举类型自动添加的

有一个私有的构造方法,接受name和ordinal,传递给父类,私有表示不能在外部创建新的实例。

例子:

public enum Size {
    SMALL, MEDIUM, LARGE
}

转换为:

public final class Size extends Enum<Size> {
    public static final Size SMALL = new Size("SMALL",0);
    public static final Size MEDIUM = new Size("MEDIUM",1);
    public static final Size LARGE = new Size("LARGE",2);
    
    private static Size[] VALUES =
            new Size[]{SMALL,MEDIUM,LARGE};
    
    private Size(String name, int ordinal){
        super(name, ordinal);
    }
    
    public static Size[] values(){
        Size[] values = new Size[VALUES.length];
        System.arraycopy(VALUES, 0,
                values, 0, VALUES.length);
        return values;
    }
    
    public static Size valueOf(String name){
        return Enum.valueOf(Size.class, name);
    }
}

枚举值实际上是静态变量,也是final的,不能被修改。

一般枚举变量会被转换为对应的静态变量;而在switch语句中,枚举值会被转换为其对应的ordinal值

加了实例变量和方法的基本实现原理

枚举转换后的类增加了对应的变量和方法,修改了构造方法
例子:

public enum Size {
    SMALL("S","小号"),
    MEDIUM("M","中号"),
    LARGE("L","大号");
    
    private String abbr;
    private String title;
    
    private Size(String abbr, String title){
        this.abbr = abbr;
        this.title = title;
    }

    public String getAbbr() {
        return abbr;
    }

    public String getTitle() {
        return title;
    }
    
    public static Size fromAbbr(String abbr){
        for(Size size : Size.values()){
            if(size.getAbbr().equals(abbr)){
                return size;
            }
        }
        return null;
    }
}

转换为:

public final class Size extends Enum<Size> {
  public static final Size SMALL = new Size("SMALL",0, "S", "小号");     
  public static final Size MEDIUM = new Size("MEDIUM",1,"M","中号");      
  public static final Size LARGE = new Size("LARGE",2,"L","大号");       
                                          
  private String abbr;                    
  private String title;                   
                                          
  private Size(String name, int ordinal,  String abbr, String title){         
      super(name, ordinal);               
      this.abbr = abbr;                   
      this.title = title;                 
  }
  //... 其他代码
}  

常规用法

每个枚举值经常有一个关联的标示(id),通常用int整数表示,使用整数可以节约存储空间,减少网络传输。一个自然的想法是使用枚举中自带的ordinal值,但ordinal并不是一个好的选择。

为什么呢?因为ordinal的值会随着枚举值在定义中的位置变化而变化,但一般来说,我们希望id值和枚举值的关系保持不变,尤其是表示枚举值的id已经保存在了很多地方的时候。

比如说,上面的Size例子,Size.SMALL的ordinal的值为0,我们希望0表示的就是Size.SMALL的,但如果我们增加一个表示超小的值XSMALL呢?

public enum Size {
    XSMALL, SMALL, MEDIUM, LARGE
}

这时,0就表示XSMALL了。

所以,一般是增加一个实例变量表示id,使用实例变量的另一个好处是,id可以自己定义。比如说,Size例子可以写为:

public enum Size {
    XSMALL(10), SMALL(20), MEDIUM(30), LARGE(40);
    
    private int id;
    private Size(int id){
        this.id = id;
    }
    public int getId() {
        return id;
    }
}

高级用法

枚举还有一些高级用法,比如说,每个枚举值可以有关联的类定义体,枚举类型可以声明抽象方法,每个枚举值中可以实现该方法,也可以重写枚举类型的其他方法。

比如说,我们看改后的Size代码

public enum Size {
    SMALL {
        @Override
        public void onChosen() {
            System.out.println("chosen small");
        }
    },MEDIUM {
        @Override
        public void onChosen() {
            System.out.println("chosen medium");
        }
    },LARGE {
        @Override
        public void onChosen() {
            System.out.println("chosen large");
        }
    };
    
    public abstract void onChosen();
} 

Size枚举类型定义了onChosen抽象方法,表示选择了该尺寸后执行的代码,每个枚举值后面都有一个类定义体{},都重写了onChosen方法。

这种写法有什么好处呢?如果每个或部分枚举值有一些特定的行为,使用这种写法比较简洁。

对于这个例子,比如说,在switch语句中根据Size对象的值执行不同的代码;
switch的缺陷是,定义swich的代码和定义枚举类型的代码可能不在一起,如果新增了枚举值,应该需要同样修改switch代码,但可能会忘记;而如果使用抽象方法,则不可能忘记,在定义枚举值的同时,编译器会强迫同时定义相关行为代码。所以,如果行为代码和枚举值是密切相关的,使用以上写法可以更为简洁、安全、容易维护。

这种写法内部是怎么实现的呢?每个枚举值都会生成一个类,这个类继承了枚举类型对应的类,然后再加上值特定的类定义体代码,枚举值会变成这个子类的对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值