第19章枚举类型

1、关键字enum可以将一组具名的值的有限集合创意为一种新的类型,而这些具有的值可以作为常规的程序组件使用。
19.1 基本enum特性
1、

package com19;

/**
 * Created by Panda on 2018/5/20.
 */
enum Shrubbery{GROUND,CRAWLING,HANGING}
public class EnumClass {
    public static void main(String[] args) {
        for (Shrubbery s:Shrubbery.values()) {
            //ordinal() 方法返回一个int值
            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("-------------------");
        }
        /**
         *GROUND  ordinal: 0
         -1
         false
         false
         class com19.Shrubbery
         GROUND
         -------------------
         CRAWLING  ordinal: 1
         0
         true
         true
         class com19.Shrubbery
         CRAWLING
         -------------------
         HANGING  ordinal: 2
         1
         false
         false
         class com19.Shrubbery
         HANGING
         -------------------
         */
    }
}

19.1.1 将静态导入用于enum
19.2向enum中添加新方法
1、除了不能继承自一个enum外,基本可以将enum看作一个常规的类。也就是可以向enum中添加方法,甚至可以有main方法
2、如果打算定义自己的方法,那么必须在enmu实力序列的最后添加一个分好。同时,Java要求必须先定义enum实例。如果在定义实例之前定义了任何方法或属性,那么在编译时就会得到错误信息。
3、Enum中的构造器与方法和普通的类没有区别,因为除了有少许控制之外,enum就是一个普通的类。所以,可以使用enum做许多事情。
19.2.1覆盖enum的方法
1、

package com19;

/**
 * Created by Panda on 2018/5/20.
 */
public enum SpaceShip {
    SCOUT,CARGO,TRAN,CURI,BATT,MOTH;
    public String toString(){
        String id=name();
        String lower=id.substring(1).toLowerCase();
        return id.charAt(0)+lower;
    }

    public static void main(String[] args) {
        for (SpaceShip s:values()) {
            System.out.println(s);
        }
    }
}

19.3 switch语句中的enum

package com19;

/**
 * Created by Panda on 2018/5/20.
 */
enum Signal{GREEN,YELLOW,RED,}
public class TrafficLight {
    Signal color=Signal.RED;
    public void change(){
        switch (color){
            case RED:color=Signal.GREEN;
                 break;
            case GREEN:color=Signal.YELLOW;
                 break;
            case YELLOW:color=Signal.RED;
                 break;
        }
    }
    public String toString(){
        return "The traffic light is  "+color;
    }

    public static void main(String[] args) {
        TrafficLight trafficLight = new TrafficLight();
        for (int i = 0; i < 7; i++) {
            System.out.println(trafficLight);
            trafficLight.change();
        }
    }
    /**
     * The traffic light is  RED
     The traffic light is  GREEN
     The traffic light is  YELLOW
     The traffic light is  RED
     The traffic light is  GREEN
     The traffic light is  YELLOW
     The traffic light is  RED
     */
}

19.4 values()的神秘之处
Values()是由编译器添加的static方法。
19.5实现,而非继承
1、enum继承自java.lang.Enum类。由于java不支持多重继承,所以enum不能再继承其他类。可以同时实现一个或多个接口。
19.6 随机选取
1、

package com19;

import java.util.Random;

/**
 * Created by Panda on 2018/5/20.
 */
public class Enums {
    private static Random random= new Random(47);
    public static <T extends  Enum<T>> T random(Class<T> tClass){
        return  random(tClass.getEnumConstants());
    }
    public static <T> T random(T[] values){
        return values[random.nextInt(values.length)];
    }
}

19.7使用接口组织枚举
1、无法从enum继承子类。在一个接口的内部,创建实现该接口的枚举,以此奖元素进行分组,可以达到将枚举元素分类组织的目的。
19.8 使用EnumSet替代标志
1、不能从enum中删除或者添加元素。
2、EnumSet的优点是:说明一个二进制位是否存在,具有更好的表达能力,并且无需担心性能。

package com19下;

import java.util.EnumSet;

import static com19下.AlarmPoints.*;

/**
 * Created by Panda on 2018/5/21.
 */
public class EnumSets {
    //STAIRI1,STAIR2,LOBBY,OFFICE1,OFFICE2,OFFICE3,OFFICE4,OFFICE5,OFFICE,BATHROOM,UTILITY,KITCHEN
    public static void main(String[] args) {
        EnumSet<AlarmPoints> pointss = EnumSet.noneOf(AlarmPoints.class);
        pointss.add(BATHROOM);
        System.out.println(pointss);

        pointss.addAll(EnumSet.of(STAIRI1,STAIR2,KITCHEN));
        System.out.println(pointss);

        pointss=EnumSet.allOf(AlarmPoints.class);
        pointss.removeAll(EnumSet.of(STAIRI1,STAIR2,KITCHEN));
        System.out.println(pointss);

        pointss.removeAll(EnumSet.range(OFFICE1,OFFICE4));
        System.out.println(pointss);

        //创建一个其元素类型与指定枚举 set 相同的枚举 set,最初包含指定 set 中所不 包含的此类型的所有元素
        pointss=EnumSet.complementOf(pointss);
        System.out.println(pointss);
    }
    /**
     * [BATHROOM]
     [STAIRI1, STAIR2, BATHROOM, KITCHEN]
     [LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, OFFICE5, OFFICE, BATHROOM, UTILITY]
     [LOBBY, OFFICE5, OFFICE, BATHROOM, UTILITY]
     [STAIRI1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN]
     */
}

19.9 使用EnumMap
1、EnumMap是一种特殊的Map,要求其中的键(key)必须来自一个enum。
2、命令模式首先需要一个只有单一方法的接口,然后从该接口实现具有各自不同的行为的多个子类。

package com19下;

import java.util.EnumMap;
import java.util.Map;

import static com19下.AlarmPoints.BATHROOM;
import static com19下.AlarmPoints.KITCHEN;
import static com19下.AlarmPoints.UTILITY;

/**
 * Created by Panda on 2018/5/21.
 */
interface Command{ void action();}
public class EnumMaps {
    public static void main(String[] args) {
        EnumMap<AlarmPoints,Command> enumMap = new EnumMap<AlarmPoints, Command>(AlarmPoints.class);
        enumMap.put(KITCHEN, new Command() {
            @Override
            public void action() {
                System.out.println("Kitchen fire");
            }
        });
        enumMap.put(BATHROOM, new Command() {
            @Override
            public void action() {
                System.out.println("Bathroom alert");
            }
        });
        for(Map.Entry<AlarmPoints,Command> e:enumMap.entrySet()){
            System.out.println(e.getKey()+" ");
            e.getValue().action();
        }
        try{
            enumMap.get(UTILITY).action();
        }catch (Exception e){
            System.out.println(e);
        }
    }
    /**
     * BATHROOM
     Bathroom alert
     KITCHEN
     Kitchen fire
     java.lang.NullPointerException
     */
}

19.10常量相关的方法
1、程序员可以为enum实例编写方法,从而为每个enum实例赋予各自不同的行为。需要为enum定义一个或多个abstract方法,然后为每个enum实例实现该抽象方法。对于内部的enum的实例而言,其行为与一般的内部类并不相同。

package com19下;

import java.util.EnumSet;

/**
 * Created by Panda on 2018/5/21.
 */
public class CarWash {
    public enum Cycle{
        UNDERBODY{
            void action(){
                System.out.println("Spraying the underbody");
            }
        },
        WHEELWASH{
            void action(){
                System.out.println("washing the wheels");
            }
        },
        PREWASH{
            void action(){
                System.out.println("Loosening the dirt");
            }
        },
        BASIC{
            void action(){
                System.out.println("The basic wash");
            }
        },
        HOTWAX{
            void action(){
                System.out.println("Applying hot wax");
            }
        },
        RINSE{
            void action(){
                System.out.println("Rinsing");
            }
        },
        BLOWDRY{
            void action(){
                System.out.println("Blowing dry");
            }
        };
        abstract void action();
    }
    EnumSet<Cycle> cycles = EnumSet.of(Cycle.BASIC,Cycle.RINSE);
    public void add(Cycle cycle){cycles.add(cycle);}
    public void washCar(){
        for (Cycle c:cycles) {
            c.action();
        }
    }
    public String toString(){
        return cycles.toString();
    }

    public static void main(String[] args) {
        CarWash carWash = new CarWash();
        System.out.println(carWash);
        carWash.washCar();

        carWash.add(Cycle.BLOWDRY);
        carWash.add(Cycle.BLOWDRY);  //忽略
        carWash.add(Cycle.RINSE);
        carWash.add(Cycle.HOTWAX);
        System.out.println(carWash);
        carWash.washCar();
    }
    /**
     * [BASIC, RINSE]
     The basic wash
     Rinsing
     [BASIC, HOTWAX, RINSE, BLOWDRY]
     The basic wash
     Applying hot wax
     Rinsing
     Blowing dry
     */
}

19.11多路分发
1、Java只支持单路分发。也就是说,如果要执行的操作包含不知一个类型未知的对象时,那么Java的动态绑定机制只能处理其中一个的类型。
2、多路分发:多态只能发生在方法调用时,所以,如果想使用两路分发,就必须有两个方法调用:第一个方法调用决定第一个未知类型,第二个方法调用决定第二个未知的类型。利用多路分发,程序员必须为每一个类型提供一个实际的方法调用,如果要处理两个不同的类型体系,就需要为每个类型体系执行一个方法调用。
3、配置好多路分发需要很多工序,好处在于方法调用时的优雅的语法。
4、

package com19下;


import java.util.Random;

import static com19下.OutCome.DRAW;
import static com19下.OutCome.LOSE;
import static com19下.OutCome.WIN;

/**
 * Created by Panda on 2018/5/21.
 */

interface Item{
    OutCome compete(Item it);
    OutCome eval(Paper p);
    OutCome eval(Scissors s);
    OutCome eval(Rock r);
}
class Paper implements Item{
    @Override
    public OutCome compete(Item it) {
        return it.eval(this);
    }

    @Override
    public OutCome eval(Paper p) {
        return DRAW;
    }

    @Override
    public OutCome eval(Scissors s) {
        return WIN;
    }

    @Override
    public OutCome eval(Rock r) {
        return LOSE;
    }

    public String toString(){return "paper";}
}
class Scissors implements Item{
    @Override
    public OutCome compete(Item it) {
        return it.eval(this);
    }

    @Override
    public OutCome eval(Paper p) {
        return LOSE;
    }

    @Override
    public OutCome eval(Scissors s) {
        return DRAW;
    }

    @Override
    public OutCome eval(Rock r) {
        return WIN;
    }
    public String toString(){return "Scissors";}
}

class Rock implements Item{
    @Override
    public OutCome compete(Item it) {
        return it.eval(this);
    }

    @Override
    public OutCome eval(Paper p) {
        return WIN;
    }

    @Override
    public OutCome eval(Scissors s) {
        return LOSE;
    }

    @Override
    public OutCome eval(Rock r) {
        return DRAW;
    }
    public String toString(){return "Rock";}
}
  public class RoShamBo1{
    static final  int SIZE=20;
    private static Random random = new Random(47);
    public static Item newItem(){
        switch (random.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());
          }
      }
  }

19.11.1使用enum分发
1、使用构造器初始化每个enum实例,并以“一组”结果作为参数,这两者放在一块,形成类似查询表的结构。
19.11.2 使用常量相关的方法
19.11.3使用EnumMap分发
1、使用EnumMap能够实现“真正的”两路分发。EnumMap是为enum专门设计的一种性能非常好的特殊Map。
19.11.4使用二维数组
19.12总结

猜你喜欢

转载自blog.csdn.net/Panda_____/article/details/80386134