zoukankan      html  css  js  c++  java
  • Enum 类型

    枚举类型(Enumerated Type)

    什么是枚举?

    枚举是一个被命名的整型常数的集合。在多种编程语言中都有使用(C/C++/c#/java等

    示例

    public enum Size {
        S, M, L
    };

    为什么使用枚举?

    在JDK1.5 之前,定义常量都是: public static fianl …… 。

    类常量

    public class Size {
        public static final int S = 1;
        public static final int M = 2;
        public static final int L = 3;
    }

    接口常量

    public interface Size {
        public static final int S = 1;
        public static final int M = 2;
        public static final int L = 3;
    }

     使用

    System.out.println(Size.L);//3

    但是这种方式存在一些缺陷,详见下面使用枚举与直接定义常量的比较。

    所以在5.0 版本 SDK中,在语言层面上增加了枚举类型。

    创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。

    枚举可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法(如添加字段,方法,遍历访问)。

    枚举可以用在变量的类型匹配的检测中,可以提前发现编程错误。

    枚举定义了一个变量的可使用范围。能够使程序可读性提高。

    在编译期间限定类型,不允许发生越界的情况。 

    和一般的类中使用接口一样,enum枚举中同样可以实现接口,并实现接口中的所有方法,这样做的好处在于可以更方便地对枚举中的值进行排序、比较等操作,封装性更好。


    使用枚举与直接定义常量的比较

    1、两种引用方式相同,都是类名.属性”。

    2、常量是直接编译在代码中的,而枚举则是一种类,你可以通过反射根据值反查出它的枚举形式是什么。

    3、枚举可只定义枚举项而不定义枚举值,而类常量(或接口常量)则必须定义值,否则编译失败;

    4、常量不是数据类型,只是说明被定义数据是不可变的常量;枚举是一种数据类型。

    5、枚举定义了一组类型相同的成员且成员的语义清晰;常量也可以是一个数组(比如int[]),虽然其中元素类型相同,但是没法清晰指出其中元素的意义。

    6、类常量可以被继承,枚举类型是不能有继承的,也就是说一个枚举常量定义完毕后,除非修改重构,否则无法做扩展。 


    注意:

    enum 类型不支持 public 和 protected 修饰符的构造方法,因此构造函数一定要是 private 或 默认的。所以枚举对象是无法在程序中通过直接调用其构造方法来初始化的。

    所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。enum枚举类型是一个不可以被继承的final类。

    定义 enum 类型时候,如果是简单类型,那么最后一个枚举值后不用跟任何一个符号;但如果有定制方法,那么最后一个枚举值与后面代码要用分号';'隔开,不能用逗号或空格。

    由于 enum 类型的值实际上是通过运行期构造出对象来表示的,所以在 cluster(集群) 环境下,每个虚拟机都会构造出一个同义的枚举对象。因而在做比较操作时候就需要注意,如果直接通过使用等号 ( ‘ == ’ ) 操作符,这些看似一样的枚举值一定不相等,因为这不是同一个对象实例。


    方法

    1、toString

    返回枚举常量名。

    System.out.println(Size.L.toString());//L

    2、valueOf(Class, String)

    Size s = (Size) Enum.valueOf(Size.class, "L");
    System.out.println(s.toString());// L

    3、values()

    返回一个包含全部枚举值的数组。

    Size[] arr = Size.values();
            for (Size s : arr) {
                System.out.println(s);//依次输出S、M、L
            }

    4、ordinal()

    返回枚举常量的位置,位置从0开始计数。

    System.out.println(Size.M.ordinal());//1

    枚举集合(EnumSet)

    JDK5.0 中也增加了两个工具类 EnumSet 和 EnumMap,都放在 java.util 包中。

    EnumSet 是一个针对枚举类型的高性能的 Set 接口实现。EnumSet 中装入的所有枚举对象都必须是同一种类型。

    EnumSet保证集合中的元素不重复;

    枚举 set 在内部表示为位向量。此表示形式非常紧凑且高效。此类的空间和时间性能应该很好,足以用作传统上基于 int 的“位标志”的替换形式,具有高品质、类型安全的优势。

    如果其参数也是一个枚举 set,则批量操作(如 containsAllretainAll)也应运行得非常快。 

    EnumSet 支持在枚举类型的所有值的某个范围中进行迭代。

    EnumMap中的 key是enum类型,而value则可以是任意类型。

    注意

    像大多数 collection 实现一样,EnumSet 是不同步的。

    如果多个线程同时访问一个枚举 set,并且至少有一个线程修改该 set,则此枚举 set 在外部应该是同步的。这通常是通过对自然封装该枚举 set 的对象执行同步操作来完成的。

    如果不存在这样的对象,则应该使用 Collections.synchronizedSet(java.util.Set) 方法来“包装”该 set。最好在创建时完成这一操作,以防止意外的非同步访问。

     Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));

    方法

    1、range(E from, E to)

    创建一个最初包含由两个指定端点所定义范围内的所有元素的枚举 set。

    for (Size s : EnumSet.range(Size.M, Size.L)) {
                System.out.println(s);// 依次打印M、L
            }

    2、有多个of方法用于创建一个最初包含指定元素的枚举 set。


    枚举集合(EnumMap)

    EnumMap 是一个高性能的 Map 接口实现。

    EnumMap中的 key是enum类型,而value则可以是任意类型。

    枚举映射在内部表示为数组。此表示形式非常紧凑且高效。

    EnumMap 将丰富的和安全的 Map 接口与数组快速访问结合到一起,如果你希望要将一个枚举类型映射到一个值,你应该使用 EnumMap。

    枚举映射根据其键的自然顺序 来维护(该顺序是声明枚举常量的顺序)。

    注意

    像大多数 collection 一样,EnumMap不同步的。

    如果多个线程同时访问一个枚举映射,并且至少有一个线程修改该映射,则此枚举映射在外部应该是同步的。这一般通过对自然封装该枚举映射的某个对象进行同步来完成。

    如果不存在这样的对象,则应该使用 Collections.synchronizedMap(java.util.Map<k, v="">) 方法来“包装”该枚举。最好在创建时完成这一操作,以防止意外的非同步访问。

         Map<EnumKey, V> m
             = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));

    应用

    switch (Size.M) {
            case S:
                System.out.println("小");
                break;
            case M:
                System.out.println("中 ");
                break;
            default:
                System.out.println("无");
            }

    自定义

    public enum Size {
        // Java要求必须先定义 enum 实例。必须在enum实例序列的最后添加一个分号。
        S(1, "small", "小"), M(2, "middle", "中"), L(3, "large", "大");
        // 定义私有变量
        private int code;
        private String en;
        private String cn;
    
        // 构造函数,只能为私有或默认
        private Size(int code, String en, String cn) {
            this.code = code;
            this.en = en;
            this.cn = cn;
        }
    
        // 覆盖toString方法
        public String toString() {
            return this.name() + "(编号:" + this.code + ",英文:" + this.en + ",中文:"
                    + this.cn + ")";
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getEn() {
            return en;
        }
    
        public void setEn(String en) {
            this.en = en;
        }
    
        public String getCn() {
            return cn;
        }
    
        public void setCn(String cn) {
            this.cn = cn;
        }
    }

    调用

    Size[] arr = Size.values();
    for (Size s : arr) {
    System.out.println(s);
    }

    打印

    S(编号:1,英文:small,中文:小)
    M(编号:2,英文:middle,中文:中)
    L(编号:3,英文:large,中文:大)

    enum与class的关系?

    代码:

    public enum Size {
        S, M, L
    };

    反编译:

    反编译后可以发现:

    1、生成了一个Size类,该类继承了java.lang.Enum。

    2、Size类被final修饰,可知枚举不能被继承。

    3、属性是public static final,可知枚举项是常量,在定义枚举项时尽量用大写。

    可以把枚举看成是一个不能被继承的类。

  • 相关阅读:
    LeetCode 226. Invert Binary Tree
    LeetCode 221. Maximal Square
    LeetCode 217. Contains Duplicate
    LeetCode 206. Reverse Linked List
    LeetCode 213. House Robber II
    LeetCode 198. House Robber
    LeetCode 188. Best Time to Buy and Sell Stock IV (stock problem)
    LeetCode 171. Excel Sheet Column Number
    LeetCode 169. Majority Element
    运维工程师常见面试题
  • 原文地址:https://www.cnblogs.com/SQP51312/p/6066927.html
Copyright © 2011-2022 走看看