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. 平面最近点对(HDU 1007)

    题解:点击 #include <stdio.h> #include <string.h> #include <algorithm> #include <ios ...

  2. linux进程同步之信号量

    首先了解一下,信号量机概念是由荷兰科学家Dijkstr引入,值得一提的是,它提出的Dijksrtr算法解决了最短路径问题. 信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享 ...

  3. tomcat中配置JNDI方法

    1.项目中spring的数据源配置: <bean id="dataSource" class="org.springframework.jndi.JndiObjec ...

  4. HTML5<canvas>标签:使用canvas元素在网页上绘制渐变和图像(2)

    详细解释HTML5 Canvas中渐进填充的参数设置与使用,Canvas中透明度的设置与使用,结合渐进填充与透明度支持,实现图像的Mask效果. 一:渐进填充(Gradient Fill) Canva ...

  5. 颜色采集器colpick Color Picker

    简单 RGB.HSB.十六进制颜色选取器 jQuery 插件. 非常直观类似 Photoshop 的界面. 光明和黑暗很容易自定义 CSS3 外观. 28 KB 总由浏览器加载看起来不错甚至在 IE7 ...

  6. Educational Codeforces Round 55 (Rated for Div. 2):C. Multi-Subject Competition

    C. Multi-Subject Competition 题目链接:https://codeforces.com/contest/1082/problem/C 题意: 给出n个信息,每个信息包含专业编 ...

  7. oracle的rownum使用

    对于rownum来说它是Oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,且rownum不能以任何表的名称作为前缀. ...

  8. nginx 设置ip地址访问,但是设置域名访问不了

    一.导语 在Nginx的设置过程中,ip地址能正常访问的,但是把ip地址转换成域名,就访问不了了,这个是怎么回事呢?今天来探讨一下 二.设置ip地址做负载均衡 2.1.server端 server { ...

  9. xmlns:sys="clr-namespace:System;assembly=mscorlib" NOTE: System;与assembly中间不能有空格

    xmlns:sys="clr-namespace:System;assembly=mscorlib"  NOTE: System;与assembly中间不能有空格 否则报错, Er ...

  10. 在Ubuntu下编译WebKit源码--qt

    转载自:http://www.cnblogs.com/panderen/archive/2011/10/18/2216154.html 在朋友的介绍下有幸認识了WebKit这个让人心动的开源浏览器内核 ...