首页 > 编程语言 > 详细

Java中的枚举类型

时间:2021-06-02 09:17:12      阅读:17      评论:0      收藏:0      [点我收藏+]

枚举类型

枚举类型是Java1.5中新增的特性,它是一种特殊的数据类型。之所以特殊是因为它既是一种类类型(class)却又比类类型多了些特殊的约束,但这些约束的存在也造就了枚举类型的简洁性、安全性和便捷性。

枚举类的使用场景

  • 类的对象数量是有限且固定的
  • 定义一组相关常量时强烈建议使用枚举类型
  • 可以在switch中使用枚举类型
  • 可以使用枚举类型实现单例模式

关于枚举类型

  1. 使用enum定义的枚举类默认继承的是抽象类:java.lang.Enum,而不是Object类,可以实现多个接口。
  2. 枚举类的所有实例(即该枚举类的实例)都必须放在第一行( ; 结尾)。不需要显式调用构造器
  3. 使用enum定义的非抽象枚举类默认使用final修饰,不可被继承
  4. 枚举类的构造器是私有的
  5. toString方法返回的就是枚举实例的名称

定义一个简单的枚举类

public class EnumDemo {
  public static void main(String[] args) {
    Season spring = Season.SPRING;
    System.out.println(spring);
  }
}

enum Season{
  SPRING, SUMMER, FALL, WINTER;
}
  • 在第一行写枚举类的实例的时候,默认调用了构造器,如果使用的不是默认的无参构造,就要创建有参构造

  • 构造器需要定义成私有的,枚举类通常设计成不可变类,它的Filed属性不应该被改变,这样会更加安全,代码更加简洁

枚举类的基本实现原理

在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum类,也就是说通过关键字enum创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类。

这个类长这个样子

final class Day extends Enum
{
    //编译器为我们添加的静态的values()方法
    public static Day[] values()
    {
        return (Day[])$VALUES.clone();
    }
    //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
    public static Day valueOf(String s)
    {
        return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
    }
    //私有构造函数
    private Day(String s, int i)
    {
        super(s, i);
    }
     //前面定义的7种枚举实例
    public static final Day MONDAY;
    public static final Day TUESDAY;
    public static final Day WEDNESDAY;
    public static final Day THURSDAY;
    public static final Day FRIDAY;
    public static final Day SATURDAY;
    public static final Day SUNDAY;
    private static final Day $VALUES[];

    static 
    {    
        //实例化枚举实例
        MONDAY = new Day("MONDAY", 0);
        TUESDAY = new Day("TUESDAY", 1);
        WEDNESDAY = new Day("WEDNESDAY", 2);
        THURSDAY = new Day("THURSDAY", 3);
        FRIDAY = new Day("FRIDAY", 4);
        SATURDAY = new Day("SATURDAY", 5);
        SUNDAY = new Day("SUNDAY", 6);
        $VALUES = (new Day[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }
}

从上面反编译得来的代码可以发现:(这代码是copy过来的)

  • 生成的这个类继承自Enum,而且是final的,无法被扩展
  • 编译器帮我们生成了枚举类中定义的实例对象(一一对应),这充分说明了枚举类中的枚举常量也是实实在在的枚举类实例对象
  • 编译器还为我们生成了两个静态方法,分别是values()和 valueOf()

Enum类中的常用方法:

  1. compareTo(E o):比较此枚举与指定对象的顺序
  2. equals(Object other):当指定对象等于此枚举常量时,返回 true
  3. getDeclaringClass():返回与此枚举常量的枚举类型相对应的 Class 对象
  4. name():返回此枚举常量的名称,在其枚举声明中对其进行声明
  5. ordinal():返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)
  6. toString():返回枚举常量的名称,它包含在声明中
  7. static valueOf(String name):返回带指定名称的枚举常量
  8. static values():获取枚举类中的所有变量,并作为数组返回

可以向枚举类添加自定义的构造函数和方法

enum Season implements Info{
  SPRING("春天"),
  SUMMER("夏天"),
  FALL("秋天"),
  WINTER("冬天");

  private String desc;
  //将构造函数私有化
  private Season(String desc){
    this.desc = desc;
  }

  public String getDesc() {
    return desc;
  }

枚举类中定义抽象方法和实现接口

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

enum Season implements Info{
  SPRING("春天"){
    @Override
    public String getInfo() {
      return info();
    }

    @Override
    public String info() {
      return "春天有点儿绿";
    }
  },
  SUMMER("夏天"){
    @Override
    public String getInfo() {
      return info();
    }

    @Override
    public String info() {
      return "夏天有点儿热";
    }
  },
  FALL("秋天"){
    @Override
    public String getInfo() {
      return info();
    }

    @Override
    public String info() {
      return "秋天有点儿黄";
    }
  },
  WINTER("冬天") {
    @Override
    public String getInfo() {
      return info();
    }

    @Override
    public String info() {
      return "冬天有点儿冷";
    }
  };

  private String desc;

  private Season(String desc){
    this.desc = desc;
  }

  public String getDesc() {
    return desc;
  }

  public abstract String getInfo();
}

枚举与switch

使用switch进行条件判断时,条件参数一般只能是整型,字符型。而枚举型确实也被switch所支持,在java 1.7后switch也对字符串进行了支持。

枚举与单例模式

单例模式可以说是最常使用的设计模式了,它的作用是确保某个类只有一个实例,自行实例化并向整个系统提供这个实例。在实际应用中,线程池、缓存、日志对象、对话框对象常被设计成单例,总之,选择单例模式就是为了避免不一致状态。

关于单例,我们总是应该记住:保证线程安全,延迟加载,序列化与反序列化安全,反射安全是很重要的。

枚举单例的实现

//非常简单,你想加什么代码自己看着办
public enum Singleton {
  INSTANCE;
}

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

Java中的枚举类型

原文:https://www.cnblogs.com/codeloong/p/14839066.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!