《Java 编程思想》--第十九章:枚举类型

  1. 关键字enum可以将一组具名的值得优先级和创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用
  2. enum的定义和使用方式方式:
    1. 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      enum Shrubbery {GROUND, CRAWLING, HANGING}
       
      public class EnumClass {
       
           public static void main(String[] args) {
               // TODO Auto-generated method stub
               for (Shrubbery s : Shrubbery.values()){
                   System.out.println(s + " ordinal:" + s.ordinal());
                   System.out.println(s.compareTo(Shrubbery.CRAWLING) + "  " );
                   System.out.println(s.equals(Shrubbery.CRAWLING));
                   System.out.println(s == Shrubbery.CRAWLING);
                   System.out.println(s.getDeclaringClass());
                   System.out.println(s.name());
                   System.out.println();
               }
           }
       
      }

    2. values()返回enum实例数组,并且该数组的元素严格保持其在enum中声明时的顺序
    3. ordinal()方法返回一个int值,表示每个enum实例在声明时的次序
    4. 可以直接使用==来比较enum实例,编译器会自动为你提供equals()和hashCode()方法。Enum类实现了Comparable接口,所以它具有compareTo()方法。同时它还实现了Serializable接口
    5. getDeclaringClass()方法可以获得其所属的enum类
    6. name()方法与使用toString()方法效果相同,返回enum实例声明时的名字
    7. valueOf()是Enum中定义的static方法,根据给定的名字返回相应的enum实例,如果不存在给定名字的实例,将会抛出异常
  3. 静态导入enum:
    1. 使用方式:
      1. 1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        package enumTest;
         
        public enum Spiciness {
             NOT, MILD, MEDIUM, HOT, FLAMING
        }
         
        package enumTest;
         
        import static enumTest.Spiciness.*;
         
        public class Burrito {
         
             public static void main(String[] args) {
                 System.out.println(NOT.ordinal());
                 System.out.println(MILD);
                 System.out.println(MEDIUM.equals(MILD));
             }
         
        }

      2. 通过static import,可以使enum实例的标识符带入当前的命名空间,所以无需再用enum类型来修是谁enum实例
  4. enum不能被继承,除此之外可以将其看作是一个常规的类,可以向其中添加方法,甚至可以有main()方法
    1. 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      package enumTest;
       
      public enum OzWitch {
           WEST( "This is west" ),
           NORTH( "This is north" ),
           EAST( "This is east" ),
           SOUTH( "This is center" );
           
           private String description;
           private OzWitch(String description) {
               this .description = description;
           }
           
           public String getDescription(){
               return description;
           }
           
           public static void main (String[] args) {
               for (OzWitch witch : OzWitch.values()){
                   System.out.println(witch.toString() + ":" + witch.getDescription());
               }
           }
      }

  5. values()的神秘之处
    1. 编译器创建的enum类都继承自Enum类,然而Enum类中并没有values()方法。values()方法是由编译器添加的static方法,在创建一个enum类时,编译器还为其添加了valueOf()方法,在Enum中的valueOf()需要两个参数,而这个新增的valueOf()方法只需要一个
    2. 编译器还将enum类标记为final类,所以无法继承自enum类
    3. 由于values()方法是由编译器插入到enum定义中的static方法,所以如果将enum实例向上转型为Enum,那么values()方法就不可访问了。
    4. 在Class中有一个getEnumConstants()方法, 可以通过Class对象取得所有的enum实例。这个方法时Class上的方法,甚至可以对不是枚举的类调用此方法并返回null
  6. 实现,而非继承
    1. 所有的enum类都继承自java.lang.Enum类,由于Java不支持多重继承,所以enum不能继承其他类
  7. 随机选取:
    1. 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      package enumTest;
       
      enum Activity {SITTING, LYING, STANDING, HOPPING, RUNNING, DODGING, JUMPING, FALLING, FLYING}
       
      public class RandomTest {
       
           public static void main(String[] args) {
               for ( int i = 0 ; i < 20 ; i++){
                   System.out.println(Enums.random(Activity. class ));
               }
           }
       
      }
       
      package enumTest;
       
      import java.util.Random;
       
      public class Enums {
       
           private static Random rand = new Random( 47 );
           
           public static <T extends Enum<T>>T random(Class<T> ec){
               return random(ec.getEnumConstants());
           }
           
           public static <T> T random(T[] values){
               return values[rand.nextInt(values.length)];
           }
       
      }

  8. 使用接口组织枚举:
    1. 对于enum而言,实现接口是使其子类化的唯一方法,所以嵌入在Food中的每个enum都实现了Food接口
      1. 1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        package enumTest;
         
        public interface Food {
             enum Appetizer implements Food{
                 SALAD, SOUP, SPRINT_ROLLS;
             }
             
             enum MainCourse implements Food{
                 LASAGNE, BURRITO, PAD_THAI, LENTITLS, HUMMOUS, VINDALOO;
             }
             //And so on....
        }
         
        package enumTest;
         
        import static enumTest.Food.*;
         
        public class TypeOfFood {
         
             public static void main(String[] args) {
                 Food food = Appetizer.SALAD;
                 food = MainCourse.BURRITO;
             }
         
        }

    2. 如果类型数量较多,接口就不如enum好用了,可以建立枚举的枚举,甚至是在enum中嵌套enum
      1. 1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        package enumTest;
         
        public enum Meal {
             APPETIZER(Food.Appetizer. class ),
             MAINCOURSE(Food.MainCourse. class ),
             DESSERT(Food.Dessert. class ),
             COFFEE(Food.Coffee. class );
             private Food[] values;
             
             private Meal(Class<? extends Food> kind){
                 values = kind.getEnumConstants();
             }
             
             public interface Food {
                 enum Appetizer implements Food{
                     SALAD, SOUP, SPRING_ROLLS;
                 }
                 enum MainCourse implements Food{
                     LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALLO;
                 }
                 enum Dessert implements Food{
                     TIRAMISU, GELATO, BLACK_FOREST_CAKE, FRUIT, VREME_CARAMEL;
                 }
                 enum Coffee implements Food {
                     BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, LATTE, CAPPUCCINO, TEA, HERB_TEA;
                 }
             }
             
             public Food randomSelection(){
                 return Enums.random(values);
             }
             
             public static void main (String[] args){
                 for ( int i = 0 ; i < 5 ; i++){
                     for (Meal meal : Meal.values()){
                         Food food = meal.randomSelection();
                         System.out.println(food);
                     }
                     System.out.println( "---" );
                 }
             }
        }

  9. 使用EnumSet替代标志:
    1. Java SE5中引入EnumSet,为了通过enum创建一种替代品,以替代传统的基于int的“位操作”。这种标志可以用来表示某种“开/关”信息。
    2. EnumSet的设计充分考虑到了速度因素,其操作与HashSet相比,非常的快,就其内部而言,它(可能)就是将一个long值作为b比特向量。
    3. 使用EnumSet的优点是:说明一个二进制位是否存在,具有更好的表达能力,并且无需担心性能
    4. EnumSet的元素必须来源于一个enum
    5. 使用实例:
      1. 1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        package enumTest;
         
        import static enumTest.AlarmPoints.*;
         
        import java.util.EnumSet;
         
        public class EnumSets {
         
             public static void main(String[] args) {
                 EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints. class );
                 points.add(BATHROOM);
                 System.out.println(points);
                 points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
                 System.out.println(points);
                 points = EnumSet.allOf(AlarmPoints. class );
                 System.out.println(points);
                 points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
                 System.out.println(points);
                 points.removeAll(EnumSet.range(OFFICE1,OFFICE4));
                 System.out.println(points);
                 points = EnumSet.complementOf(points);
                 System.out.println(points);
             }
         
        }

      2. 1
        2
        3
        4
        5
        package enumTest;
         
        public enum AlarmPoints {
             STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN
        }
      3. of方法被重载了很多次,因为其实只是用可变参数已经可以解决整个问题,但是对比显示的参数会有一点性能损失。当使用一个参数或多过5个参数时,调用的僵尸使用可变参数的of()方法,由于使用一个参数时,编译器不会构造可变参数的数组所以调用一个参数没有额外的性能消耗
    6. EnumSet的基础是long,一个long值有64位,但EnumSet可以应用于多过64个元素的enum,所以猜测,Enum会在必要的时候增加一个long
  10. 使用EnumMap:
    1. EnumMap是一种特殊的Map,它要求其中的键必须来自一个enum。由于enum本身的限制,所以EnumMap在内部可由数组实现,因此EnumMap的速度非常快。除了必须使用enum的实例作为键来调用put()方法以外,其他和一般的Map差不多
    2. 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      package enumTest;
       
      import static enumTest.AlarmPoints.*;
       
      import java.util.EnumMap;
      import java.util.Map;
       
      public class EnumMaps {
       
           interface Command{
               void action();
           }
           
           public static void main(String[] args) {
               EnumMap<AlarmPoints, Command> em = new EnumMap<AlarmPoints, Command>(AlarmPoints. class );
               em.put(KITCHEN, new Command() {
       
                   @Override
                   public void action() {
                       System.out.println( "Kitchen fire" );
                   }
                   
               });
               em.put(BATHROOM, new Command() {
       
                   @Override
                   public void action() {
                       System.out.println( "Bathroom fire" );
                   }
                   
               });
               
               for (Map.Entry<AlarmPoints, Command> e : em.entrySet()){
                   System.out.print(e.getKey() + ":" );
                   e.getValue().action();
               }
           }
      }
       
      package enumTest;
       
      public enum AlarmPoints {
           STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN
      }
    3. 与EnumSet一样,EnumMap中的顺序由enum实例决定
  11. 可以使用enum实现职责连
  12. 枚举类型非常适合用来创建状态机。一个状态机可以具有有限个特定的状态,它通常根据输入,从一个状态转移到下一个状态,不过也可能存在瞬时状态,而一旦人数执行结束,状态机就会立即离开瞬时状态
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值