Java枚举

1 枚举的用法

1.1 常量

在JDK1.5 之前,定义常量的方法:public static fianl…

而使用枚举,可以把相关的常量分组到一个枚举类型里,并且枚举提供了比常量更多的方法。

public enum Color {  
 	RED, GREEN, BLANK, YELLOW  
}  

1.2 switch

使用枚举,增强代码可读性。

enum Signal {  
    GREEN, YELLOW, RED  
}  
public class TrafficLight {  
    Signal color = Signal.RED;  
    public void change() {  
        switch (color) {  
        case RED:  
            color = Signal.GREEN;  
            break;  
        case YELLOW:  
            color = Signal.RED;  
            break;  
        case GREEN:  
            color = Signal.YELLOW;  
            break;  
        }  
    }  
}  

1.3 向枚举中添加新方法

在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。

public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    // 普通方法  
    public static String getName(int index) {  
        for (Color c : Color.values()) {  
            if (c.getIndex() == index) {  
                return c.name;  
            }  
        }  
        return null;  
    }  
    // get set 方法  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getIndex() {  
        return index;  
    }  
    public void setIndex(int index) {  
        this.index = index;  
    }  
}  

1.4 覆盖枚举的方法

public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    //覆盖方法  
    @Override  
    public String toString() {  
        return this.index+"_"+this.name;  
    }  
}  

1.5 实现接口

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

public interface Behaviour {  
    void print();  
    String getInfo();  
}  
public enum Color implements Behaviour{  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
//接口方法  
    @Override  
    public String getInfo() {  
        return this.name;  
    }  
    //接口方法  
    @Override  
    public void print() {  
        System.out.println(this.index+":"+this.name);  
    }  
}  

1.6 使用接口组织枚举

public interface Food {  
    enum Coffee implements Food{  
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  
    }  
    enum Dessert implements Food{  
        FRUIT, CAKE, GELATO  
    }  
}  

1.7 枚举集合

2 枚举的实现

示例代码

public enum ApplicationInterfaceTypeEnum {

    dubbo("dubbo", 1), webapp("webapp", 2), custom("custom", 3);
    private String name;
    private int index;

    //私有构造,防止被外部调用
    private ApplicationInterfaceTypeEnum(String name, int index) {
        this.name = name;
        this.index = index;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

通过javap进行反汇编

Compiled from "ApplicationInterfaceTypeEnum.java"
public final class cn.zzypiper.test.enumearn.ApplicationInterfaceTypeEnum extends java.lang.Enum<cn.zzypiper.test.enumearn.ApplicationInterfaceTypeEnum> {
  public static final cn.zzypiper.test.enumearn.ApplicationInterfaceTypeEnum dubbo;

  public static final cn.zzypiper.test.enumearn.ApplicationInterfaceTypeEnum webapp;

  public static final cn.zzypiper.test.enumearn.ApplicationInterfaceTypeEnum custom;

  public static cn.zzypiper.test.enumearn.ApplicationInterfaceTypeEnum[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
       3: invokevirtual #2                  // Method "[Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;"
       9: areturn
    LineNumberTable:
      line 3: 0

  public static cn.zzypiper.test.enumearn.ApplicationInterfaceTypeEnum valueOf(java.lang.String);
    Code:
       0: ldc           #4                  // class cn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum
       2: aload_0
       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #4                  // class cn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum
       9: areturn
    LineNumberTable:
      line 3: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      10     0  name   Ljava/lang/String;

  public java.lang.String getName();
    Code:
       0: aload_0
       1: getfield      #7                  // Field name:Ljava/lang/String;
       4: areturn
    LineNumberTable:
      line 16: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;

  public void setName(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #7                  // Field name:Ljava/lang/String;
       5: return
    LineNumberTable:
      line 20: 0
      line 21: 5
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       6     0  this   Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
          0       6     1  name   Ljava/lang/String;

  public int getIndex();
    Code:
       0: aload_0
       1: getfield      #8                  // Field index:I
       4: ireturn
    LineNumberTable:
      line 24: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;

  public void setIndex(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #8                  // Field index:I
       5: return
    LineNumberTable:
      line 28: 0
      line 29: 5
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       6     0  this   Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
          0       6     1 index   I

  static {};
    Code:
       0: new           #4                  // class cn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum
       3: dup
       4: ldc           #9                  // String dubbo
       6: iconst_0
       7: ldc           #9                  // String dubbo
       9: iconst_1
      10: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;I)V
      13: putstatic     #11                 // Field dubbo:Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
      16: new           #4                  // class cn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum
      19: dup
      20: ldc           #12                 // String webapp
      22: iconst_1
      23: ldc           #12                 // String webapp
      25: iconst_2
      26: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;I)V
      29: putstatic     #13                 // Field webapp:Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
      32: new           #4                  // class cn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum
      35: dup
      36: ldc           #14                 // String custom
      38: iconst_2
      39: ldc           #14                 // String custom
      41: iconst_3
      42: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;I)V
      45: putstatic     #15                 // Field custom:Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
      48: iconst_3
      49: anewarray     #4                  // class cn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum
      52: dup
      53: iconst_0
      54: getstatic     #11                 // Field dubbo:Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
      57: aastore
      58: dup
      59: iconst_1
      60: getstatic     #13                 // Field webapp:Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
      63: aastore
      64: dup
      65: iconst_2
      66: getstatic     #15                 // Field custom:Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
      69: aastore
      70: putstatic     #1                  // Field $VALUES:[Lcn/zzypiper/test/enumearn/ApplicationInterfaceTypeEnum;
      73: return
    LineNumberTable:
      line 5: 0
      line 3: 48
}

可以把 enum 看成是一个普通的 class,它们都可以定义一些属性和方法,不同之处是:enum 不能使用 extends 关键字继承其他类,因为 enum 已经继承了 java.lang.Enum(java是单一继承)。

3 Enum类

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

    private final String name;

    public final String name() {
        return name;
    }

    private final int ordinal;

    public final int ordinal() {
        return ordinal;
    }

    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    public String toString() {
        return name;
    }

    public final boolean equals(Object other) {
        return this==other;
    }

    public final int hashCode() {
        return super.hashCode();
    }

    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

    protected final void finalize() { }

    private void readObject(ObjectInputStream in) throws IOException,
        ClassNotFoundException {
        throw new InvalidObjectException("can't deserialize enum");
    }

    private void readObjectNoData() throws ObjectStreamException {
        throw new InvalidObjectException("can't deserialize enum");
    }
}

4 枚举与单例

以下是枚举实现的单例模式

public enum Singleton {

    INSTANCE;

    public void doSomething() {
        System.out.println("doSomething");
    }
}

模拟反序列化攻击

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String path ="EnumSingleton.ser";
        //Write Obj to file
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
        oos.writeObject(Singleton.INSTANCE);
        //Read Obj from file
        File file = new File(path);
        ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file));
        Singleton newInstance = (Singleton) ois.readObject();
        //判断是否是同一个对象
        System.out.println(Singleton.INSTANCE == newInstance); // true

        newInstance.doSomething();
    }
}

为什么说枚举是最好的Java单例实现方法?

5 Java枚举如何比较

java 枚举类比较是用==还是equals?
测试代码如下:

public enum GameEnum{
    BIG,
    SMALL,
    FATTER
}
public static void main(String[] args) {
    GameEnum s1 = GameEnum.BIG;
    GameEnum s2 = GameEnum.BIG;
    GameEnum ss1 = GameEnum.SMALL;
    System.out.println("s1 == s2:" + (s1 == s2));
    System.out.println("s1.equals(s2):" + (s1.equals(s2)));

    System.out.println("s1 == ss1:" + (s1 == ss1));
    System.out.println("s1.equals(ss1):" + (s1.equals(ss1)));
}

out:
s1 == s2:true
s1.equals(s2)true
s1 == ss1:false
s1.equals(ss1)false

可以看到,使用== 和使用equals方法的执行结果是一样的。

Enum中实现了equals方法,即使用==

    /**
     * Returns true if the specified object is equal to this
     * enum constant.
     *
     * @param other the object to be compared for equality with this object.
     * @return  true if the specified object is equal to this
     *          enum constant.
     */
    public final boolean equals(Object other) {
        return this==other;
    }

6 switch对枚举的支持

见 1.2

7 枚举的序列化

常见的单例模式都有一个比较大的问题:就是一旦实现了Serializable接口之后,序列化会破坏单例。有一种解决办法就是使用readResolve()方法来避免此事发生。

对于枚举,Java规范中定义枚举变量在JVM中是唯一的。因此在枚举类型的序列化和反序列化上,Java做了特殊的规定。
深度分析Java的枚举类型—-枚举的线程安全性及序列化问题

8 枚举的线程安全

当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。

参考

Java 枚举(enum) 详解7种常见的用法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值