zoukankan      html  css  js  c++  java
  • 如何使用Java中的Enum类

    Java1.5 中出现了枚举类型。当一个值都在一个固定的范围内变化,那就可以使用 enum 类型来定义。比如说,一周有七天,一年有四季。

    没有枚举类的时候,我们用常量来定义一组范围值的:

    public static class Season {
    		public static final int SPRING = 1;
        public static final int SUMMER = 2;
        public static final int AUTUMN = 3;
        public static final int WINTER = 4;
    }
    

    通过常量定义的方式有这样几个缺点:

    1. 类型不安全。如 Season 类所示,程序执行过程中接收的是任意一个 int 类型的值,完全可能传入一个 1 到 4 之外的值,导致错误的出现。

    2. 一致性差。int 枚举属于编译期常量,编译完成后,代码中引用的地方会直接将整数值写入。也就是说,该 Int 枚举被修改之后,所有引用它的程序都需要重新编译。

    3. 类型无指意性。Seaon 枚举值仅仅是一些无任何含义的整数值,调试期间仅仅是一些魔数。

    定义一个 enum

    《阿里巴巴Java开发手册(华山版)》中建议我们这样定义一个 enum 类:

    【参考】枚举类名带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。

    说明:枚举其实就是特殊的类,域成员均为常量,且构造方法被默认强制是私有。

    正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKNOWN_REASON。

    【推荐】如果变量值仅在一个固定范围内变化用 enum 类型来定义。

    说明:如果存在名称之外的延伸属性应使用 enum 类型,下面正例中的数字就是延伸信息,表示一年中的第几个季节。

    由此,我们可以定义一个季节的枚举类,如下所示:

    public enum SeasonEnum {
        SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);
    
        private int seq;
    
        SeasonEnum(int seq) {
            this.seq = seq;
        }
    
        public int getSeq() {
            return seq;
        }
    }
    

    enum 类

    使用 enum 定义的枚举类默认继承 java.lang.Enum

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

    java.lang.Enum

    变量

    // enum 实例的名字
    private final String name;
    // 定义enum实例的顺序,从0开始计数
    private final int ordinal;
    

    方法

    // 返回enum实例的名称,eg. SeasonEnum.SPRING.name() - output: SPRING
    public final String name() { return name;}
    // 返回enum实例的顺序,eg. SeasonEnum.SPRING.ordinal() - output: 0
    public final int ordinal() { return ordinal;}
    // enum实例 -> 字符串 eg. SeasonEnum.SPRING.toString() - output: SPRING
    public String toString() { return name;}
    // 比较是不是一个constant,即两个enum实例的顺序(oridnal)是否相同
    public final int compareTo(E o) { ... return self.ordinal - other.ordinal; }
    // 比较是不是同一个对象
    public final boolean equals(Object other) { return this==other;}
    // 返回声明枚举常量的类的类对象
    public final Class<E> getDeclaringClass(){...}
    // 返回指定name的enum实例
    public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {}
    
    // values()是编译器产生的一个方法,API中没有,可以用来遍历
    public static SeasonEnum getSeasonByOrdinal(int seq) {
    	for (SeasonEnum season: SeasonEnum.values()) {
    		if(season.getSeq() == seq) {
    			return season;
    		}
    	}
    	return null;
    }
    

    enum 的用法

    用法一:定义常量

    也就是最开始说的,enum 出现之后,用 enum 来代替常量类型。

    public static class Season {
    		public static final int SPRING = 1;
        public static final int SUMMER = 2;
        public static final int AUTUMN = 3;
        public static final int WINTER = 4;
    }
    
    public enum SeasonEnum {
        SPRING, SUMMER, AUTUMN, WINTER;
    }
    

    用法二:switch

    Java1.5 推出了 enum,Java1.6 支持在 switch 中使用 enum 类型。

    
    public enum OperationUseSwitch {
    	PLUS, MINUS, TIMES, DIVIDE;
     
    	double apply(double x, double y) {
    		switch (this) {
    			case PLUS:
    				return x + y;
    			case MINUS:
    				return x - y;
    			case TIMES:
    				return x * y;
    			case DIVIDE:
    				return x / y;
    		}
    		// 如果this不属于上面四种操作符,抛出异常
    		throw new AssertionError("Unknown operation: " + this);
    	}
    }
    

    用法三:特定于常量的方法实现

    特定于常量的方法实现指的是,在 enum 类中定义一个抽象方法,然后各个枚举常量需要实现这个方法。这样做的优点在于,相对于 switch 语句,抽象程度更高,每个 enum 实例都需要实现统一的方法,不会漏下。

    public enum Operation {
    	PLUS {
    		double apply(double x, double y) {
    			return x + y;
    		}
    	},
    	MINUS {
    		double apply(double x, double y) {
    			return x - y;
    		}
    	},
    	TIMES {
    		double apply(double x, double y) {
    			return x * y;
    		}
    	},
    	DIVIDE {
    		double apply(double x, double y) {
    			return x / y;
    		}
    	};
     
    	abstract double apply(double x, double y);
    }
    

    用法四:实现接口

    enum 类都隐式得继承自 java.lang.Enum,而 Java 只支持单继承,所有 enum 类不能再继承其它类,但是可以实现接口。比如用法三中将统一的方法抽象出来,就可以使用接口来实现:

    public interface Behavior {
        double apply(double x, double y);
    }
    
    public enum  Operation implements Behavior{
        PLUS {
            public double apply(double x, double y) {
                return x + y;
            }
        },
        MINUS {
            public double apply(double x, double y) {
                return x - y;
            }
        },
        TIMES {
            public double apply(double x, double y) {
                return x * y;
            }
        },
        DIVIDE {
            public double apply(double x, double y) {
                return x / y;
            }
        };
    }
    

    用法五:覆盖 Enum 的方法

    public class Test {
        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;
            }
        }
    
        public static void main(String[] args) {
            System.out.println(Color.RED.toString());
        }
    }
    

    EnumSet 和 EnumMap

    EnumSet 和 EnumMap 是两个为枚举而设计的集合。EnumSet保证集合中的元素不重复;EnumMap中的 key 是enum 类型,而 value 则可以是任意类型。

    EnumMap

    public class Herb {
        public enum Type { ANNUAL, PERENNIAL, BIENNIAL }
     
        private final String name;
        private final Type type;
        
        Herb(String name, Type type) {
            this.name = name;
            this.type = type;
        }
     
        @Override public String toString() {
            return name;
        }
    }
    
    public static void main(String[] args) {
        Herb[] garden = { new Herb("Basil", Type.ANNUAL),
                new Herb("Carroway", Type.BIENNIAL),
                new Herb("Dill", Type.ANNUAL),
                new Herb("Lavendar", Type.PERENNIAL),
                new Herb("Parsley", Type.BIENNIAL),
                new Herb("Rosemary", Type.PERENNIAL) };
     
        // Using an EnumMap to associate data with an enum - Page 162
        Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type, Set<Herb>>(
                Herb.Type.class);
        for (Herb.Type t : Herb.Type.values())
            herbsByType.put(t, new HashSet<Herb>());
        for (Herb h : garden)
            herbsByType.get(h.type).add(h);
        System.out.println(herbsByType);
     
    }
    

    EnumSet

    EnumSet 是枚举类型的高性能 Set 实现,它要求放入它的枚举常量必须属于同一枚举类型。EnumSet 提供了许多工厂方法以便于初始化。

    方法名称 描述
    allOf(Class element type) 创建一个包含指定枚举类型中所有枚举成员的 EnumSet 对象
    complementOf(EnumSet s) 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象, 并包含所有 s 中未包含的枚举成员
    copyOf(EnumSet s) 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象, 并与 s 包含相同的枚举成员
    noneOf(<Class elementType) 创建指定枚举类型的空 EnumSet 对象
    of(E first,e...rest) 创建包含指定枚举成员的 EnumSet 对象
    range(E from ,E to) 创建一个 EnumSet 对象,该对象包含了 from 到 to 之间的所有枚 举成员

    EnumSet 作为 Set 接口实现,它支持对包含的枚举常量的遍历。

    for(Operation op:EnumSet.range(Operation.PLUS,Operation.MULTIPLY)) {
        doSomeThing(op);
    }
    

    参考文献

    W3CSchool-Java枚举

    Java 语言中 Enum 类型的使用介绍

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

    Java枚举 —— 很少被使用,或许是因为真正了解它的人太少了

    Java枚举(enum)详解:Java声明枚举类型、枚举(enum)类、EnumMap 与 EnumSet

  • 相关阅读:
    JS事件类型详解
    migrate的使用
    phpMyAdmin安装教程
    Unable to verify your data submission错误解决
    安装yii2高级应用模板
    关于模型中的几个概念或知识点
    视图被渲染的几种方式
    统计学与大数据分析
    物联网、云计算、大数据、人工智能概念如何区分
    物联网、云计算、大数据、人工智能概念如何区分
  • 原文地址:https://www.cnblogs.com/shuiyj/p/12046178.html
Copyright © 2011-2022 走看看