1.基本enum特征

  • 所有创建的枚举类都继承自抽象类 java.lang.Enum;
  1. 一个枚举类,所有实例都要在第一句写出以 ,隔开。 如果只有实例最后可以不加 ; 枚举类因为继承了Enum,所以再不能继承别的类,任何类也不能继承枚举类(构造器默认为private)。

    public enum Color {
    RED,
    BLUE,
    YELLOW,
    PURPLE
    }
    注意 :RED,BLUE 这些是由 enum Color类调用默认private构造器创建的实例对象,和普通class相比只不过enum的实例对象只能在内部创建。时刻记着他们是一个实例对象。
  2. 枚举类实例不能在外部 new 出来 ,因为枚举类构造器为private 一般也不用声明private,默认就是private,因为enum实例只能在编译期间enum类内部被创建,但可以外部得到一个实例的引用。
            Color red  = Color.RED;
    Color blue = Color.BLUE;
  3. 枚举类的一些方法
    1.  使用枚举元素  Color.RED 或者 red
    2.  Color.values( ) 返回一个枚举类数组,数组元素就是枚举的实例。
    3.  red.ordinal() 方法返回该实例声明的次序从0开始。
    4.  2个实例可用 == 比较
    5.  Enum 实现了 Comparable<E>和 Serializable 可以使用comparableTo( )方法,可以序列化
    6.  a. getDeclaringClass() 返回 Color.class 对象
    7.  a.name和a.toString( )方法一样。
    8. valuesOf(string ) 返回一个实例对象 Color b = Color.valueOf("BLUE");
    9.  根据class对象返回实例  Color b = Color.valueOf( Color.class,  "BLUE" )
  4. 通过带参构造器为枚举实例添加描述信息。调用 getDes()就可以的到当前对象的描述信息。
    public enum Color {
    RED("这是红色"),
    BLUE("这是蓝色"),
    YELLOW("这是黄色"),
    PURPLE("这是紫色");
    String des;
    Color( String s) {
    this.des = s;
    }
    public String getDes(){
    return des;
    }
    }

    调用 getDes( )方法就可以的到当前对象的描述信息。

  5. 重写toString( )方法来为enum实例添加描述信息。

    public enum Color {
    RED,
    BLUE,
    YELLOW,
    PURPLE; @Override
    public String toString() {
    String id = name();
    return id + " is " + id.toLowerCase();
    }
    }

    通过name() 拿到当前对象名字。

2.enum的特殊方法。

  • 除了不能继承enum类外,enum和其普通类没区别,可以添加字段,方法,甚至是main 方法
  1. enum 实例也可以用在 switch语句中
  2. values()方法不在Enum中 它是由编译器添加的static方法。
  3. 编译器还添加了一个valuesOf(String s)方法,这个只需要一个参数就可以的得到实例,而Enum的需要2个。
  4. 如果将enum向上转型为Enum那么values 和 valuesOf 无法再使用。
  5. 与values 方法有相同作用的就是Class对象的getEnumConstants(),如果class是枚举类那么返回元素数组,不是枚举类返回null

3. 使用接口组织枚举

  • 为了实现扩展enum 或者将enum分类,因为无法继承所以靠扩展子类无法实现,可以利用接口来达到这些功能。
  1. 接口内部创建实现该接口的enum 达到分类目的,并且可以向上转型为接口

    public interface Food {
    enum Fruit implements Food{
    APPLE, BANANA, ORANGE;
    }
    enum Vegetables implements Food{
    TOMATO, POTATO, BEANS;
    }
    enum Drink implements Food{
    COFFEE, COCA, REDBULL;
    }
    } public static void main(String[] args) {
    Food food = Food.Fruit.APPLE;
    food = Food.Drink.REDBULL;
    food = Food.Vegetables.BEANS;
    }
  2. 接口基础上创建一个枚举的枚举,通过该enum控制其他enum,而不是不同的类型分别都要向上转型为Food ,类多时分别向上转型不如每个用一个enum控制方便。
    public enum Course {
    FRUIT(Food.Fruit.class),
    DRINK(Food.Drink.class),
    VEGETABLES(Food.Vegetables.class);
    private Food[] values;
    Course(Class<? extends Food> kind) {
    this.values = kind.getEnumConstants();
    }
    public Food[] getValues() {
    return values;
    }
    }

    通过实例调用getValues方法就可以的到该实例的所有元素。

  3. enum嵌套在另一个enum 重新组织1 2 代码合二为一
    public enum Course {
    FRUIT(Food.Fruit.class),
    DRINK(Food.Drink.class),
    VEGETABLES(Food.Vegetables.class);
    private Food[] values; Course(Class<? extends Food > kind) {
    this.values = kind.getEnumConstants();
    } interface Food {
    enum Fruit implements Food {
    APPLE, BANANA, ORANGE;
    } enum Vegetables implements Food {
    TOMATO, POTATO, BEANS;
    } enum Drink implements Food {
    COFFEE, COCA, REDBULL;
    }
    } public Food[] getValues() {
    return values;
    } }

4. EnumSet

  • EnumSet (抽象类)一个用来存放enum 元素的Set,存取enum速度非常快,性能非常高。
  1. EnumSet 只能存放enum元素,不能插入空元素。
  2. 放入的元素位置和enum中保持一样,它处于排序状态,是一个有序Set.
  3. Enum 是个抽象类且方法除了colon( )克隆一个EnumSet外都是静态方法返回值都是EnumSet。
      EnumSet<Color> enumSet = EnumSet.noneOf(Color.class); //创建一个空集
    EnumSet<Color> enumSet2 = EnumSet.allOf(Color.class); //把集合中所有元素添加进去
    EnumSet<Color> enumSet3 = EnumSet.of(RED);//添加一个元素

    EnumSet不止这几个方法,对于of() 方法重载了6次,当传入2-5个参数调用相应方法,传入1个或者5个以上调用可变参数。

5.EnumMap

  • 特殊Map(类),key必须是enum, 由于enum元素有限所以内部只是由数组实现。
  1. 这是一个有序map,保持enum的元素顺序。
  2. EnumMap<Color,Object> map = new EnumMap<Color, Object>(Color.class);
  3. 方法和其他Map一样。

6.实例对象添加方法

  • 为每一个enum实例(相当于常量)添加一个方法,让他们有不同的行为。
  1. 为每一个实例添加不同行为的方法
    1. 在enum中创建一个或者多个abstract 方法,因为是enum的实例所以就得实现这些方法。

         RED{
      @Override
      String getInfo() {
      return null;
      } @Override
      String getTime() {
      return null;
      }
      };
      abstract String getInfo();
      abstract String getTime();
    2. enum也可以有main方法作为enum执行入口
    3. 常量添加方法后和有了类的行为,貌似和内部类一样,但他们有着不同行为,enum的常量不能作为方法参数类型,因为他们不是类,只是enum类型的static final 实例
    4. 由于enum的常量是 static final 的所以常量的方法不能访问外部类的非静态方法。
  2. 覆盖常量相关的方法
    1. enum中所有非抽象方法每个实例都可以调
    2. 如果不需要每个实例都实现抽象类,那么就可以不用定义抽象类,每个实例各自实现方法,实现的方法可以覆盖enum中的方法。
  3. 使用enum职责链。
    • 多种不同的方式解决问题,然后把它们连接在一起,但一个请求到达时遍历整个链,直到解决问题。
    • enum非常适合作为解决某一个问题的职责链,请求到达时遍历整个enum,直到解决问题。
      import java.util.EnumSet;
      import java.util.Random; public enum COR {
      SOLUTION_ONE{
      @Override
      boolean Solve(int i) {
      if (i == 1){
      System.out.println(name()+" 解决问题 " +i);
      return true;
      } return false;
      }
      },
      SOLUTION_TWO{
      @Override
      boolean Solve(int i) {
      if (i == 2){
      System.out.println(name()+" 解决问题 " +i);
      return true;
      }return false;
      }
      },
      SOLUTION_THREE{
      @Override
      boolean Solve(int i) {
      if (i == 3){
      System.out.println(name()+" 解决问题 " +i);
      return true;
      }return false;
      }
      },
      SOLUTION_FOUR{
      @Override
      boolean Solve(int i) {
      if (i == 4){
      System.out.println(name()+" 可以解决问题 " +i);
      return true;
      }return false;
      }
      }; abstract boolean Solve(int i); public static void main(String[] args) {
      Random random = new Random();
      EnumSet<COR> cors = EnumSet.allOf(COR.class);
      for (int i = 0; i < 6; i++) {
      int id = random.nextInt(4)+1;
      for (COR cor :cors) {
      if (cor.Solve(id)){
      System.out.println(" 解决问题 " +id);
      break;
      }
      }
      }
      } }
  4. enum状态机
    • 状态机可以具有 有限个 状态,通常根据输入,从一个状态转移到下一个状态,也可以有瞬时状态,一但任务结束就立刻离开瞬时状态。

7.多路分发

  • 多种类型交互时有时并不能确定所有类型,如: NUM.complete(NUM) , NUM 是所有数字类型的超类,a.complete(b) ,a b可能是同种类型也可能不是同一种类型。
  • Java 动态绑定只能处理一种类型,属于单路分发(分派),动态绑定能将complete绑定到分路a。只有方法调用才会执行动态绑定。
  1. 可以为每一个分发实现自己的动态绑定

    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) {
    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());
    }
    }
  2. 使用enum实现多路分发
    1. enum的实例不能作为类型参数,不可以重载方法。
    2. 可以使用enum构造器初始化每个enum实例,并以一组结果作为参数如 ENUM_A( vsA_DRAW,  vsB_LOSE,  vsC_WIN ) 在比较方法中使用switch 判断 返回 结果
      package enums;
      
      import static enums.OutCome.*;
      
      public enum RoSham {
      PAPER(DRAW, LOSE, WIN),
      SCISSORS(WIN, DRAW, LOSE),
      ROCK(LOSE, WIN, DRAW); private OutCome vPAPER, vSCISSORS, vROCK; RoSham(OutCome paper, OutCome scissors, OutCome rock) {
      this.vPAPER = paper;
      this.vSCISSORS = scissors;
      this.vROCK = rock;
      } public OutCome complete(RoSham it) {
      switch (it) {
      default:
      case PAPER:
      return vPAPER;
      case SCISSORS:
      return vSCISSORS;
      case ROCK:
      return vROCK;
      }
      } public static void main(String[] args) {
      System.out.println(PAPER.complete(ROCK));
      }
      }

      PAPER.complete()时把PAPER构造器中的结果与 OutCome 变量绑定,根据对比的参数返回对比结果,因此实例构造器中的参数位置非常重要、

  3. 使用EnumMap
    • EnumMap实现真正的多路分发

      package enums;
      
      import java.util.EnumMap;
      
      import static enums.OutCome.*;
      
      public enum RoShamBo {
      PAPER, SCISSORS, ROCK;
      static EnumMap<RoShamBo, EnumMap<RoShamBo, OutCome>>
      table = new EnumMap<RoShamBo, EnumMap<RoShamBo, OutCome>>(RoShamBo.class); static {
      for (RoShamBo it : RoShamBo.values()) { table.put(it, new EnumMap<RoShamBo, OutCome>(RoShamBo.class));
      } initRow(PAPER, DRAW, LOSE, WIN);
      initRow(SCISSORS, WIN, DRAW, LOSE);
      initRow(ROCK, LOSE, WIN, DRAW); } static void initRow(RoShamBo it, OutCome vPAPER, OutCome vSCISSORS, OutCome vROCK) {
      EnumMap<RoShamBo, OutCome> row = RoShamBo.table.get(it);
      row.put(RoShamBo.PAPER, vPAPER);
      row.put(RoShamBo.SCISSORS, vSCISSORS);
      row.put(RoShamBo.ROCK, vROCK);
      } public OutCome complete(RoShamBo it) {
      return table.get(this).get(it);
      } public static void main(String[] args) {
      System.out.println(ROCK.complete(SCISSORS));
      } }

      complete方法实现了2次分发

  4. 使用二维数组
    • 简单,速度快,代码易懂,但是组数比较大时尺寸容易错

        private static OutCome[][] tables = {
      {DRAW, LOSE, WIN},
      {WIN, DRAW, LOSE},
      {LOSE, WIN, DRAW},
      }; public OutCome completes (RoShamBo other) {
      return tables[this.ordinal()][other.ordinal()];
      }

知识点

  1. 可以静态导入枚举类 直接使用枚举实例 import static ......Color.* 最好使用静态导入省去写enum类。

《Java编程思想》笔记 第十九章 枚举类型的更多相关文章

  1. java编程思想笔记(1)

    java编程思想笔记(1) 一,对象的创建和生命周期 对象的数据位于何处?怎样控制对象的生命周期? 在堆(heap)的内存池中动态地创建对象. java完全采用了动态内存分配方式. 二,垃圾回收器 自 ...

  2. Java编程思想 笔记

    date: 2019-09-06 15:10:00 updated: 2019-09-24 08:30:00 Java编程思想 笔记 1. 四类访问权限修饰词 \ 类内部 本包 子类 其他包 publ ...

  3. #Java编程思想笔记(一)——static

    Java编程思想笔记(一)--static 看<Java编程思想>已经有一段时间了,一直以来都把笔记做在印象笔记上,今天开始写博客来记录. 第一篇笔记来写static关键字. static ...

  4. 2.1(java编程思想笔记)位移操作

    java位移操作主要有两种: 有符号位移:有符号位移会保留原有数字正负性,即正数依然是正数,负数依然是负数. 有符号位左移时,低位补0. 有符号右移时:当数字为正数,高位补0.当数字为负时高位补1. ...

  5. Java编程思想学习(五)----第5章:初始化与清理

    随着计算机革命的发展,“不安全”的编程方式已逐渐成为编程代价高昂的主因之一. C++引入了构造嚣(constructor)的概念,这是一个在创建对象时被自动调用的特殊方法.Java中也采用了构造器,并 ...

  6. java编程思想第四版第九章习题

    第三题 package net.mindview.interfaces; abstract class Base{ public Base(){ print(); } abstract void pr ...

  7. Java编程思想笔记

    打好java基础 后续会增加相应基础笔试题 目录如下 1 对象导论2 一切都是对象3 操作符4 控制执行流程5 初始化与清理6 访问控制权限7 复用类8 多态9 接口10 内部类11 持有对象12 通 ...

  8. java编程思想第四版第二章要点总结

    1. 基本类型 基本类型 二进制位数 包装器类 boolean - Boolean byte 8 Byte char 16 Character short 16 Short int 32 Intege ...

  9. 【Java编程思想笔记】注解--元注解

    参考文章:(小白的小小白的白 )https://blog.csdn.net/weixin_42315600/article/details/80630669 https://www.cnblogs.c ...

随机推荐

  1. c# 自动关机代码

    #region 关机代码 //C#关机代码 // 这个结构体将会传递给API.使用StructLayout //(...特性,确保其中的成员是按顺序排列的,C#编译器不会对其进行调整. [Struct ...

  2. zuoyebiji

  3. To Chromium之浏览器外框UI

    先不去管那些webkit,V8 engine, Parser, security,IPC... 先来看看Chromium的外框UI是那些code负责的,如果自己可以定制化一下,应该蛮好玩的. TBD. ...

  4. Configuring Dojo with dojoConfig - The Dojo Toolkit

    转载自Dojo官网 Configuring Dojo with dojoConfig The dojoConfig object (formerly djConfig) allows you to s ...

  5. Redis学习笔记之基础篇

    Redis是一款开源的日志型key-value数据库,目前主要用作缓存服务器使用. Redis官方并没有提供windows版本的服务器,不过微软官方开发了基于Windows的Redis服务器Micro ...

  6. oracle约束条件

    约束条件有5种 非空约束(not null):约束该列一定要输入值 主关键字约束(primary key):用来唯一标示表中的一个列,一个表中的主键约束只能有一个 外关键字约束(foreign key ...

  7. AGC016B Colorful Hats(构造)

    题目大意: 给定n和n个数,每个数a[i]代表除了i外序列中颜色不同的数的个数,问能否构造出来这个数列. 比较简单,首先先求出来a数列的最大值Max, 如果有数小于Max-1,那么显然是不存在的 接下 ...

  8. BZOJ1044 [HAOI2008]木棍分割 【二分+Dp】

    1044: [HAOI2008]木棍分割 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4281  Solved: 1644 [Submit][St ...

  9. CF858F Wizard's Tour 解题报告

    题目描述 给定一张 \(n\) 个点 \(m\) 条边的无向图,每条边连接两个顶点,保证无重边自环,不保证连通. 你想在这张图上进行若干次旅游,每次旅游可以任选一个点 \(x\) 作为起点,再走到一个 ...

  10. requestAnimationFrame实现一帧的函数节流

    用一个变量判断raf的回调是否已经执行了,已经执行了说明过了一帧,通常是16.7ms,达到了函数节流一帧的目的. var locked = false; window.addEventListense ...