zoukankan      html  css  js  c++  java
  • Java枚举类型的用法

      JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。

    1.用法一:常量

      在JDK1.5 之前,我们定义常量都是: public static fianl....(这种方式在现在项目中也很常见) 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。而且枚举类型可以帮助我们检测许多的编译失误。

    例如:

    package enumTest;
    
    public enum Color {
        RED,BLANK,YELLOW
    }

    测试代码:

    package enumTest;
    
    public class Test {
        public static void main(String[] args) {
            String string = Color.BLANK.toString();
            System.out.println(string);
            System.out.println(Color.BLANK);
        }
    }

    BLANK
    BLANK

    2.用法二:switch

      JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。 

        public static void main(String[] args) {
            Color color = Color.RED;
            switch (color) {
            case BLANK:
                System.out.println("黑色");
                break;
            case RED:
                System.out.println("红色");
                break;
            default:
                break;
            }
        }

    结果:

      红色

    3.用法三:向枚举中添加新方法

      如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号而且 Java 要求必须先定义 enum 实例。 且枚举类型的构造方法必须为私有方法。

    package enumTest;
    
    public enum MyDay {
        
        MONDAY(1,"星期一"),THUSDAY(2,"星期二");//这个后面必须有分号
        
        private int code;
        private String name;
        private MyDay(int code,String name) {
            this.code = code;
            this.name = name();
        }
        
        public int getCode() {
            return code;
        }
        public String getName() {
            return name;
        }
        public void setCode(int code) {
            this.code = code;
        }
        public void setName(String name) {
            this.name = name;
        }
        
    }

    测试类:

        public static void main(String[] args) {
            System.out.println(MyDay.MONDAY.getCode());
            System.out.println(MyDay.MONDAY.getName());
            System.out.println(MyDay.THUSDAY.getCode());
            System.out.println(MyDay.THUSDAY.getName());
            System.out.println(MyDay.THUSDAY);
        }

    结果:

    1
    MONDAY
    2
    THUSDAY
    THUSDAY

      注意:枚举类型中可以有静态方法,也可以与其他方法。可以有属性与get,set方法。

    4.用法四:覆盖枚举的方法

    例如:覆盖toString()方法

    package enumTest;
    
    public enum MyDay {
        
        MONDAY(1,"星期一"),THUSDAY(2,"星期二");//这个后面必须有分号
        
        private int code;
        private String name;
        private MyDay(int code,String name) {
            this.code = code;
            this.name = name();
        }
        
        public int getCode() {
            return code;
        }
        public String getName() {
            return name;
        }
        public void setCode(int code) {
            this.code = code;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return this.getName()+"---"+this.getCode();
        }
    }

    测试:

    package enumTest;
    
    public class Test {
        public static void main(String[] args) {
            System.out.println(MyDay.MONDAY.getCode());
            System.out.println(MyDay.MONDAY.getName());
            System.out.println(MyDay.THUSDAY.getCode());
            System.out.println(MyDay.THUSDAY.getName());
            System.out.println(MyDay.THUSDAY);
        }
    }

    结果:

    1
    MONDAY
    2
    THUSDAY
    THUSDAY---2

    利用javap反汇编查看编译好的class文件:  继承自Enum类

    $ javap -c MyDay.class
    Compiled from "MyDay.java"
    public final class enumTest.MyDay extends java.lang.Enum<enumTest.MyDay> {
      public static final enumTest.MyDay MONDAY;
    
      public static final enumTest.MyDay THUSDAY;
    
      public static enumTest.MyDay[] values();
        Code:
           0: getstatic     #1                  // Field $VALUES:[LenumTest/MyDay;
           3: invokevirtual #2                  // Method "[LenumTest/MyDay;".clone:                                                                                                                ()Ljava/lang/Object;
           6: checkcast     #3                  // class "[LenumTest/MyDay;"
           9: areturn
    
      public static enumTest.MyDay valueOf(java.lang.String);
        Code:
           0: ldc_w         #4                  // class enumTest/MyDay
           3: aload_0
           4: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Lj                                                                                                                ava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
           7: checkcast     #4                  // class enumTest/MyDay
          10: areturn
    
      public int getCode();
        Code:
           0: aload_0
           1: getfield      #7                  // Field code:I
           4: ireturn
    
      public java.lang.String getName();
        Code:
           0: aload_0
           1: getfield      #9                  // Field name:Ljava/lang/String;
           4: areturn
    
      public void setCode(int);
        Code:
           0: aload_0
           1: iload_1
           2: putfield      #7                  // Field code:I
           5: return
    
      public void setName(java.lang.String);
        Code:
           0: aload_0
           1: aload_1
           2: putfield      #9                  // Field name:Ljava/lang/String;
           5: return
    
      public java.lang.String toString();
        Code:
           0: new           #10                 // class java/lang/StringBuilder
           3: dup
           4: invokespecial #11                 // Method java/lang/StringBuilder."<                                                                                                                init>":()V
           7: aload_0
           8: invokevirtual #12                 // Method getName:()Ljava/lang/Strin                                                                                                                g;
          11: invokevirtual #13                 // Method java/lang/StringBuilder.ap                                                                                                                pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          14: ldc           #14                 // String ---
          16: invokevirtual #13                 // Method java/lang/StringBuilder.ap                                                                                                                pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          19: aload_0
          20: invokevirtual #15                 // Method getCode:()I
          23: invokevirtual #16                 // Method java/lang/StringBuilder.ap                                                                                                                pend:(I)Ljava/lang/StringBuilder;
          26: invokevirtual #17                 // Method java/lang/StringBuilder.to                                                                                                                String:()Ljava/lang/String;
          29: areturn
    
      static {};
        Code:
           0: new           #4                  // class enumTest/MyDay
           3: dup
           4: ldc           #18                 // String MONDAY
           6: iconst_0
           7: iconst_1
           8: ldc           #19                 // String ▒▒▒▒һ
          10: invokespecial #20                 // Method "<init>":(Ljava/lang/Strin                                                                                                                g;IILjava/lang/String;)V
          13: putstatic     #21                 // Field MONDAY:LenumTest/MyDay;
          16: new           #4                  // class enumTest/MyDay
          19: dup
          20: ldc           #22                 // String THUSDAY
          22: iconst_1
          23: iconst_2
          24: ldc           #23                 // String ▒▒▒ڶ▒
          26: invokespecial #20                 // Method "<init>":(Ljava/lang/Strin                                                                                                                g;IILjava/lang/String;)V
          29: putstatic     #24                 // Field THUSDAY:LenumTest/MyDay;
          32: iconst_2
          33: anewarray     #4                  // class enumTest/MyDay
          36: dup
          37: iconst_0
          38: getstatic     #21                 // Field MONDAY:LenumTest/MyDay;
          41: aastore
          42: dup
          43: iconst_1
          44: getstatic     #24                 // Field THUSDAY:LenumTest/MyDay;
          47: aastore
          48: putstatic     #1                  // Field $VALUES:[LenumTest/MyDay;
          51: return
    }

       可以看出枚举类的原理是将枚举类继承java.lang.Enum<enumTest.MyDay>,并且声明为final,其内部维护多个实例,而且是在静态代码块中进行实例化多个实例。其实普通的类构造方法声明为private,静态代码块中初始化对应的变量即可实现enum的原理代码。

    5.用法五:实现接口

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

    例如:

    package enumTest;
    
    public interface DayInterface {
    
        public String getDay();
    }
    package enumTest;
    
    public enum MyDay implements DayInterface{
        
        MONDAY(1,"星期一"),THUSDAY(2,"星期二");//这个后面必须有分号
        
        private int code;
        private String name;
        private MyDay(int code,String name) {
            this.code = code;
            this.name = name();
        }
        
        public int getCode() {
            return code;
        }
        public String getName() {
            return name;
        }
        public void setCode(int code) {
            this.code = code;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return this.getName()+"---"+this.getCode();
        }
    
        @Override
        public String getDay() {
            return this.getName();
        }
    }

    测试:

    package enumTest;
    
    public class Test {
        public static void main(String[] args) {
            System.out.println(MyDay.THUSDAY.getDay());
        }
    }

    结果:

    THUSDAY

    6.用法六:使用接口组织枚举

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

    测试类:

    package enumTest;
    
    import enumTest.Food.Coffee;
    import enumTest.Food.Dessert;
    
    public class Test {
            
        public  static void main(String[] args) {  
            for (Dessert dessertEnum : Food.Dessert.values()) {  
                System.out.print(dessertEnum + "  ");  
            }  
            System.out.println();  
            //我这地方这么写,是因为我在自己测试的时候,把这个coffee单独到一个文件去实现那个food接口,而不是在那个接口的内部。  
            for (Coffee coffee : Food.Coffee.values()) {  
                System.out.print(coffee + "  ");  
            }  
            System.out.println();  
            //搞个实现接口,来组织枚举,简单讲,就是分类吧。如果大量使用枚举的话,这么干,在写代码的时候,就很方便调用啦。  
            //还有就是个“多态”的功能吧,  
            Food food = Food.Dessert.CAKE;  
            System.out.println(food);  
            food = Coffee.BLACK_COFFEE;  
            System.out.println(food);  
        } 
    }

    结果:

    FRUIT CAKE GELATO
    BLACK_COFFEE DECAF_COFFEE LATTE CAPPUCCINO
    CAKE
    BLACK_COFFEE

    7.用法七:关于枚举集合的使用

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

     1. EnumSet的简单用法

      enumSet继承AbstractSet,AbstractSet实现了set接口。

    public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
        implements Cloneable, java.io.Serializable
    {
    。。。
    }
    
    public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
    。。。
    }

    测试代码:

    package enumTest;
    
    import java.util.EnumSet;
    import java.util.Iterator;
    
    public class Test {
        public static void main(String[] args) {
            // 创建一个EnumSet集合,其内部的值就是MyDay枚举类的实例
            EnumSet<MyDay> enumSet = EnumSet.allOf(MyDay.class);
            System.out.println(enumSet);
            Iterator<MyDay> iterator = enumSet.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
    
            // 创建一个空的EnumSet集合
            System.out.println("====================");
            EnumSet<MyDay> enumSet2 = EnumSet.noneOf(MyDay.class);
            System.out.println(enumSet2);
            enumSet2.add(MyDay.MONDAY);
            System.out.println(enumSet2);
    
            // 创建一个带有指定值的EnumSet
            System.out.println("====================");
            EnumSet<MyDay> enumSet3 = EnumSet.of(MyDay.MONDAY);
            enumSet2.add(MyDay.MONDAY);// 由于不可重复所以不会重复两个元素
            System.out.println(enumSet3);
        }
    }

    结果:

    [MONDAY---1, THUSDAY---2]
    MONDAY---1
    THUSDAY---2
    ====================
    []
    [MONDAY---1]
    ====================
    [MONDAY---1]

    2. EnumMap的简单用法

      EnumMap继承AbstractMap,AbstractMap继承实现map接口。而且EnumMap中的中key必须为枚举类型,而且不能为null

    public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
        implements java.io.Serializable, Cloneable
    。。。
    }
    
    public abstract class AbstractMap<K,V> implements Map<K,V> {
      。。。  
    }

    测试代码:

    package enumTest;
    
    import java.util.EnumMap;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Test {
        public static void main(String[] args) {
            // 创建一个空的map
            EnumMap<MyDay, Object> enumMap = new EnumMap<>(MyDay.class);
            System.out.println(enumMap);
            enumMap.put(MyDay.MONDAY, "周一");
            enumMap.put(MyDay.THUSDAY, "周四");
            System.out.println(enumMap);
    
            // 创建第二个enumMap
            EnumMap<MyDay, Object> enumMap2 = new EnumMap<>(enumMap);
            System.out.println(enumMap2);
    
            // 以普通map为参数创建第三个enumMap,要求key必须是枚举类型
            Map map = new HashMap<>();
            map.put(MyDay.MONDAY, 111);
            EnumMap<MyDay, Object> enumMap3 = new EnumMap<>(map);
            System.out.println(enumMap3);
        }
    }

    结果:

    {}
    {MONDAY---1=周一, THUSDAY---2=周四}
    {MONDAY---1=周一, THUSDAY---2=周四}
    {MONDAY---1=111}

    补充:

      1.枚举类型对象之间的值比较,是可以使用==,直接来比较值,是否相等的,不是必须使用equals方法的哟。

        public  static void main(String[] args) {  
            System.out.println(MyDay.MONDAY == MyDay.MONDAY);
            System.out.println(MyDay.MONDAY == MyDay.MONDAY);
        }

    结果:

    true
    true

      2.我们大概了解了枚举类型的定义与简单使用后,现在有必要来了解一下枚举类型的基本实现原理。

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

    C:UsersliqiangDesktop>javap -p MyDay.class
    Compiled from "MyDay.java"
    public final class MyDay extends java.lang.Enum<MyDay> {
      public static final MyDay MONDAY;
      public static final MyDay THUSDAY;
      private int code;
      private java.lang.String name;
      private static final MyDay[] $VALUES;
      public static MyDay[] values();
      public static MyDay valueOf(java.lang.String);
      private MyDay(int, java.lang.String);
      public int getCode();
      public java.lang.String getName();
      public void setCode(int);
      public void setName(java.lang.String);
      static {};
    }

      3.Enum抽象类常见方法

    Enum是所有 Java 语言枚举类型的公共基本类(注意Enum是抽象类),以下是它的常见方法:

    返回类型方法名称方法说明
    int compareTo(E o) 比较此枚举与指定对象的顺序
    boolean equals(Object other) 当指定对象等于此枚举常量时,返回 true。
    Class<?> getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象
    String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明
    int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)
    String toString() 返回枚举常量的名称,它包含在声明中
    static<T extends Enum<T>> T static valueOf(Class<T> enumType, String name) 返回带指定名称的指定枚举类型的枚举常量。

      这里主要说明一下ordinal()方法,该方法获取的是枚举变量在枚举类中声明的顺序,下标从0开始,如日期中的MONDAY在第一个位置,那么MONDAY的ordinal值就是0,如果MONDAY的声明位置发生变化,那么ordinal方法获取到的值也随之变化,注意在大多数情况下我们都不应该首先使用该方法,毕竟它总是变幻莫测的。compareTo(E o)方法则是比较枚举的大小,注意其内部实现是根据每个枚举的ordinal值大小进行比较的。name()方法与toString()几乎是等同的,都是输出变量的字符串形式。至于valueOf(Class<T> enumType, String name)方法则是根据枚举类的Class对象和枚举名称获取枚举常量,注意该方法是静态的,后面在枚举单例时,我们还会详细分析该方法,下面的代码演示了上述方法:

      4.values()方法和valueOf(String name)方法是编译器生成的static方法因此从前面的分析中,在Enum类中并没出现values()方法,但valueOf()方法还是有出现的,只不过编译器生成的valueOf()方法需传递一个name参数,而Enum自带的静态方法valueOf()则需要传递两个方法,从前面反编译后的代码可以看出,编译器生成的valueOf方法最终还是调用了Enum类的valueOf方法。

    补充:带抽象方法的枚举类型的应用

      如果我们写一个枚举类型来实现基本的运算,我们可能会写成下面:

    public enum Operation {
    
        PLUS, MINUS, TIMES, DIVIDE;
    
        public double operate(double num1, double num2) {
            switch (this) {
            case PLUS:
                return num1 + num2;
            case MINUS:
                return num1 - num2;
            case TIMES:
                return num1 * num2;
            case DIVIDE:
                return num1 / num2;
            }
    
            throw new RuntimeException("err");
        }
    
    }

      如果我们增加一个新的运算规则需要增加一个新的实例,而且增加一个case分支。

    用抽象方法+枚举替代:

    public enum Operation {
    
        PLUS {
            @Override
            double operate(double num1, double num2) {
                return num1 + num2;
            }
        },
        MINUS {
            @Override
            double operate(double num1, double num2) {
                return num1 - num2;
            }
        },
        TIMES {
            @Override
            double operate(double num1, double num2) {
                return num1 * num2;
            }
        },
        DIVIDE {
            @Override
            double operate(double num1, double num2) {
                return num1 / num2;
            }
        };
    
        abstract double operate(double num1, double num2);
    
    }
  • 相关阅读:
    streamsets 集成 cratedb 测试
    streamsets k8s 部署试用
    streamsets rest api 转换 graphql
    StreamSets sdc rpc 测试
    StreamSets 相关文章
    StreamSets 多线程 Pipelines
    StreamSets SDC RPC Pipelines说明
    StreamSets 管理 SDC Edge上的pipeline
    StreamSets 部署 Pipelines 到 SDC Edge
    StreamSets 设计Edge pipeline
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/9065264.html
Copyright © 2011-2022 走看看