Think In Java 第19章 枚举类型

本文发表于KuTear's Blog,转载请注明

  1. 默认枚举继承至Enum类,由于Java的单一继承机制,所以不能在继承至别的类.

  2. 枚举中的元素实质为类的类部静态常量域.

    public class EnumTest {
        enum Test {
            TEST_1("1"), TEST_2("2");
            private String descript;
            Test(String descript) {
                this.descript = descript;
            }
        }
    }
    

    该枚举通过反编译查看其内部(javap EnumTest$Test.class),另外,枚举类是final,不会有子类

    Compiled from "EnumTest.java"
    final class EnumTest$Test extends java.lang.Enum<EnumTest$Test> {
        public static final EnumTest$Test TEST_1;
        public static final EnumTest$Test TEST_2;
        public static EnumTest$Test[] values();
        public static EnumTest$Test valueOf(java.lang.String);
        static {};
    }
    
  3. 对于其构造函数,由于不允许用户自行实例化,构造器为privatepublic都是一样的.

  4. 静态导入,如上面的例子.再别的地使用可以使用静态导入

    import static EnumTest.Test.*
    
  5. Javaswitch子句支持的类型

    • short(Short)
    • char(Charactor)
    • byte(Byte)
    • int(Integer)
    • String
    • enum

    在Java7中引入的String本质上也是使用int来做判断的(hashCode()equals())

  6. 枚举的values()静态函数是由编译器写入.向上转型为Enum后丢失.但可以通过ClassgetEnumContants()获取到枚举元素.

  7. 枚举实现抽象方法

    enum FontConstant{
          Blod{
              @Override
              void show() {
                 //TODO
              }
          },
          Italilc{
              @Override
              void show() {
                 //TODO
              }
          },
          Plain{
              @Override
              void show() {
                 //TODO
              }
          };
          abstract void show();
    }
    
  8. EnumSetEnumMap的使用

    • EnumSet
      内部的数据的顺序与add(...)时的顺序没有关系,而是与enum中声明的顺序一致,
    public static void showEnumSet(){
          EnumSet<FontConstant> enumSet = EnumSet.noneOf(FontConstant.class);
          enumSet.add(FontConstant.Blod);
          enumSet.add(FontConstant.Plain);
          enumSet.add(FontConstant.Italilc);
          enumSet.add(FontConstant.Blod);
          for(Iterator<FontConstant> iter = enumSet.iterator(); iter.hasNext();){
              System.out.println(iter.next());
          }
    }
    

    输出:

    Blod
    Italilc
    Plain

    由此可以看见,EnumSet的顺序是与enum的声明有关,并且只能添加不重复的对象

    • EnumMap
      EnumMapEnumSet的顺序是一样的.
  9. 枚举责任链

    实现依赖与枚举的顺序

    enum Handler {
         HANDLER_1 {
             @Override
             boolean handler(Action action) {
                 return action.action == 1;
             }
         },
         HANDLER_2 {
             @Override
             boolean handler(Action action) {
                 return action.action == 2;
             }
         };
    
         abstract boolean handler(Action action);
    }
    
    public static class Action{
         int action;
    
         public Action(int action) {
             this.action = action;
         }
    }
    
    public static void handler(Action action) {
         for (Handler handler : Handler.values()) {
             if (handler.handler(action)) {
                 System.out.println(handler.name() + " Handle This Action");
                 return;
             }
         }
         System.out.println("No One Can Handle");
    }
    
    public static void main(String[] args) {
         Action a1 = new Action(1);
         handler(a1);
         Action a2 = new Action(2);
         handler(a2);
         Action a3 = new Action(3);
         handler(a3);
    }
    

    输出

    HANDLER_1 Handle This Action</br>
    HANDLER_2 Handle This Action</br>
    No One Can Handle

  10. 枚举状态机

    1个事件的完成要经过A->B->C->D四个状态,

    public void process(Status status){
      switch(status.getStatus){
        case A:
           status.setStatus(B);
           break;
        case B:
           status.setStatus(C);
           break;
        ...   
      }
    }
    

    这是使用(if/else)/switch实现,我们还可以使用enum来实现

    enum Status {
        A {
            @Override
            void process(Product pro) {
                pro.status = B;
            }
        },
        B {
            @Override
            void process(Product pro) {
                System.out.println("OK");
                pro.status = C;          //reset
            }
        },
        ...
        abstract void process(Product pro);
    }
    
    public static class Product{
        private Status status = Status.A;
        public void make(){
            status.process(this);
        }
    }
    
    public static void main(String[] args) {
        Product product = new Product();
        for (int i = 0; i < 10; i++) {
            System.out.println(product.status.name());
            product.make();
        }
    }
    
  11. 枚举多路分发

    根据对象的类型而对方法进行的选择,就是分派(Dispatch)。

  • 静态分派(编译时)

         static class A {}
         static class B extends A {}
         static class C extends A {}    
         public static void print(A obj){
             System.out.println("A");
         }
         public static void print(B obj){
             System.out.println("B");
         }
         public static void print(C obj){
             System.out.println("C");
         }
         public static void main(String[] args) {
             A a = new A();
             print(a);
             A b = new B();
             print(b);
             A c = new C();
             print(c);
         }
         ```
         输出
         > A
         > A
         > A
    
    - 动态分派(运行时)    
     ```java
     static class A {
         public void print(){
             System.out.println("A");
         }
     }
    
     static class B extends A {
         @Override
         public void print() {
             System.out.println("B");
         }
     }
     static class C extends A {
         @Override
         public void print() {
             System.out.println("C");
         }
     }
    
     public static void main(String[] args) {
         A a = new A();
         a.print();
         A b = new B();
         b.print();
         A c = new C();
         c.print();
     }
    

    输出

    A</br>
    B</br>
    C

  • 两路分发

     public enum Outcome { WIN, LOSE, DRAW } ///:~
     interface Item {
       Outcome compete(Item it);
       Outcome eval(Paper p);
       Outcome eval(Scissors s);
       Outcome eval(Rock r);
     }
    
     class Paper implements Item {
       public Outcome compete(Item it) {
           return it.eval(this);
       }
       public Outcome eval(Paper p) {
           return DRAW;
       }
       public Outcome eval(Scissors s) {
           return WIN;
       }
       public Outcome eval(Rock r) {
           return LOSE;
       }
       public String toString() {
           return "Paper";
       }
    }
    
     class Scissors implements Item {
         public Outcome compete(Item it) {
             return it.eval(this);
         }
    
         public Outcome eval(Paper p) {
             return LOSE;
         }
    
         public Outcome eval(Scissors s) {
             return DRAW;
         }
    
         public Outcome eval(Rock r) {
             return WIN;
         }
    
         public String toString() {
             return "Scissors";
         }
     }
    
     class Rock implements Item {
         public Outcome compete(Item it) {
             return it.eval(this);
         }
    
         public Outcome eval(Paper p) {
             return WIN;
         }
    
         public Outcome eval(Scissors s) {
             return LOSE;
         }
    
         public Outcome eval(Rock r) {
             return DRAW;
         }
    
         public String toString() {
             return "Rock";
         }
     }
    
     public class RoShamBo1 {
         static final int SIZE = 20;
         private static Random rand = new Random(47);
    
         public static Item newItem() {
             switch (rand.nextInt(3)) {
             default:
             case 0:
                 return new Scissors();
             case 1:
                 return new Paper();
             case 2:
                 return new Rock();
             }
         }
    
         public static void match(Item a, Item b) {
             //在这里两个参数a和b的类型都不确切,
             //通过动态调用a.compete()可以调到真实的a的compete(),
             //而在具体类型的compete通过同样的方式,获取到b的确切类型
             //在更具重载的方法调用到了具体的方法
             System.out.println(a + " vs. " + b + ": " + a.compete(b));
         }
    
         public static void main(String[] args) {
             for (int i = 0; i < SIZE; i++)
                 match(newItem(), newItem());
         }
     } 
    

    多路分发就是指在调用a.plus(b),a和b都不知道确切类型,也能让他们正常交互。
    如果想使用两路分发,那么必须有两个方法调用,第一个方法调用决定第一个未知类型,第二个方法调用决定第二个未知类型。要利用多路分发,程序员必须为每一个类型提供给一个实际的方法调用。一般而言,程序员需要设定好某种配置,以便一个方法调用能够引出更多的方法调用,从而能在这个过程中处理多个类型。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,581评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • 多态 任何域的访问操作都将有编译器解析,如果某个方法是静态的,它的行为就不具有多态性 java默认对象的销毁顺序与...
    yueyue_projects阅读 935评论 0 1
  • 一. Java基础部分.................................................
    wy_sure阅读 3,790评论 0 11
  • 今天,刚接触这个叫简书的软件,也许,该写些什么纪念一下。 如今也到了三十而立的年纪,内心当中不免又...
    疯feng峰阅读 153评论 0 0