19 枚举类型 Enumerated

关键词enum可以将一组具名的值的有限集合创建为一种新的类型, 而这些具名的值可以作为常规的程序组件使用, 这是一种非常有用的功能

  • 基本enum特性

enum Shrubbery {
    GROUND, CRAWLING, HANGING
}
public class EnumClass {
    public static void main(String[] args) throws Exception {

        //values()方法遍历enum中所有的实例
        for(Shrubbery s : Shrubbery.values()) {

            //ordinal()返回实例在enum中唯一的序号(声明时的次序)
            print(s + " oridinal: " + s.ordinal());

            //enum实现了Comaparable接口, 所以具有compareTo接口
            printnb(s.compareTo(Shrubbery.CRAWLING) + " ");

            //enum自动提供了equals()方法和hashCode()方法
            printnb(s.equals(Shrubbery.CRAWLING) + " ");
            print(s == Shrubbery.CRAWLING);

            //获取声明的enum名
            print(s.getDeclaringClass());
            print("------------");
        }
    }
}

导入enum

这是一个enum

public enum Spiciness {
    NOT, MILD, MEDIUM, HOT, FLAMING
}

静态导入这个enum

import static enumerated.Spiciness.*;
public class Burrito {
    Spiciness degree;
    public Burrito(Spiciness degree) {
        this.degree = degree;
    }
    public String toString() {
        return "Burrito is " + degree;
    }
    public static void main(String[] args) throws Exception {
        System.out.println(new Burrito(NOT));
        System.out.println(new Burrito(HOT));
    }
}

  • 向enum中添加新方法

可以向enum中添加方法, 甚至main方法

public enum OZWitch {
    WEST("west"),
    NORTH("north"),
    EAST("east"),
    SOUTH("south");

    //必须在最后一个实例的最后加一个分号
    private String description;

    //添加了一个每一个实例用一个字符串描述自身的构造器
    private OZWitch(String description) {
        this.description = description;
    }
    public String getDescription() { return this.description; }
    public static void main(String[] args) {
        for(OZWitch witch : OZWitch.values()) {
            print(witch + ": " + witch.getDescription());
        }
    }
}

覆盖enum的方法

public enum SpaceShip {
    COUT, CARGO, TRANSPORT, CRUISER, BATTLESHIP, MOTHERSHIP;

    //覆盖toString()方法, 改变输出实例的格式
    public String toString() {

        //name()返回实例的名字, 即定义时全大写的形式
        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);
        }
    }
}

  • 在switch中使用enum

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;
        }
    }
}

enum中自动存储了每个实例的序号, 用switch读取enum实例的时候, 编译器会自动帮我们调用oridinal()获取它的序号值

  • values()

enum Explore { HERE, THERE }

反编译后的Explore

Compiled from "Reflection.java"
final class enumerated.Explore extends java.lang.Enum<enumerated.Explore> {
  public static final enumerated.Explore HERE;
  public static final enumerated.Explore THERE;
  static {};
  public static enumerated.Explore[] values();
  public static enumerated.Explore valueOf(java.lang.String);
}

values()方法是编译器向enum中添加的static方法, 如果你把enum实例向上转型成Enum, 就失去这个方法了

但是在Enum的Class里有一个getEnumConstants()方法, 可以获取实例

for(Enum en : e.getClass().getEnumConstants())
            System.out.println(en);

  • 实现, 而非继承

enum都继承自Enum, 所以不能再继承其他类, 只能实现接口

随机选取

下面是一个生成随机选取实例的例子

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)];
    }
}

<T extends Enum<T>>表示T是Enum的一个实例, 将Class<T>作为参数, 就可以获取实例的数组

重载的从实例数组随机选取的方法就跟Enum类无关了

  • 使用接口组织枚举

在一个接口的内部, 创建实现该接口的枚举, 以此将枚举分组

下面这些枚举代表不同的食物种类, 它们都实现了food接口, 可以向上转型为统一的food类型

 public interface Food {
    enum Appetizer implements Food {
        SALAD, SOUP, SPRING_ROLLS
    }
    enum MainCourse implements Food {
        LASAGNE, BURRITO, PAD_THAI,
        LENTILS, HUMMOUS, VINDALOD
    }
}

可以像下面这样, 写一个枚举的枚举, 由于这些枚举都是实现了同一接口的子枚举, 可以将它们向上转型

为食物类型

public enum Course {
    APPETIZER(Food.Appetizer.class),
    MAINCOURSE(Food.MainCourse.class);
    private Food[] values;
    private Course(Class<? extends Food> kind) {
        values = kind.getEnumConstants();
    }
    public Food randomSelection() {
        return Enums.random(values);
    }
}

取出每个枚举以及它包含的实例的时候, 可以转换为food类型

for(int i = 0;i < 5;i++) {
            for(Course course : Course.values()) {
                Food food = course.randomSelection();
                System.out.println(food);
            }
            System.out.println("---");
}

或者直接把接口嵌套在一个枚举里面

public enum SecurityCategory {

    //STOCK和BOND里面存储的是接口里面定义的两个枚举的实例
    STOCK(Security.Stock.class),
    BOND(Security.Bond.class);
    private Security[] values;
    SecurityCategory(Class<? extends Security> kind) {
        values = kind.getEnumConstants();
    }
    interface Security {
        enum Stock implements Security { SHORT, LONG, MARGIN }
        enum Bond implements Security { MUNICIPAL, JUNK }
    }
    public Security randomSelection() {
        return Enums.random(values);
    }
    public static void main(String[] args) {
        for(int i = 0;i < 10;i++) {
            SecurityCategory category = 
                Enums.random(SecurityCategory.class);
            System.out.println(category.randomSelection());
        }
    }
}

  • 使用EnumSet替代标志

将一种enum类型的一些实例放进EnumSet中

public class EnumSets {
    public static void main(String[] args) throws Exception {

        //noneof()创建一个空的EnumSet

        //初始化用enum.class
        EnumSet<AlarmPoints> points = 
            EnumSet.noneOf(AlarmPoints.class);
        points.add(BATHROOM);
        print(points);
        points.addAll(EnumSet.of(START1, START2, KITCHEN));
        print(points);

        //加入整个enum
        points = EnumSet.allOf(AlarmPoints.class);
        print(points);
        points.removeAll(EnumSet.of(START1, START2, KITCHEN));
        print(points);
        points = EnumSet.complementOf(points);
    }
}

  • EnumMap

EnumMap要求其中的键必须来自一个enum,

由于enum数量的限制, 所以EnumMap内部可以由数组实现

Command用了命令模式, 是一个只有一个方法的接口

interface Command { void action(); }

public class EnumMaps {
    public static void main(String[] args) throws Exception {

        //初始化也是用enum.class
        EnumMap<AlarmPoints, Command> em = 
            new EnumMap<AlarmPoints, Command>(AlarmPoints.class);
        em.put(KITCHEN, new Command() {
            public void action() {
                print("kitchen fire!");
            }
        });
        em.put(BATHROOM, new Command() {
            public void action() {
                print("Bathroom alert!");
            }
        });
        for(Map.Entry<AlarmPoints, Command> e : em.entrySet()) {
            printnb(e.getKey() + ": ");
            e.getValue().action();
        }
        try {
            em.get(UTILITY);
        } catch(Exception e) {
            print(e);
        }
    }
}

每一个enum的实例可以在内部定义一些自己的行为, 

在enum中定义一个抽象方法, 然后为每个实例实现这个方法

public enum ConstantSpecificMethod {
    DATE_TIME {
        String getInfo() {
            return DateFormat.getDateInstance().format(new Date());
        }
    },
    CLASSPATH {
        String getInfo() {
            return System.getProperty("classpath");
        }
    },
    VERSION {
        String getInfo() {
            return System.getProperty("java.version");
        }
    };
    abstract String getInfo();
    public static void main(String[] args) {
        for(ConstantSpecificMethod csm : values())
            System.out.println(csm.getInfo());
    }
}

看上去实例就像是enum的子类一样, 用这种方式实现了多态, 实际上并不是

enum的实例只是enum的static final对象, 它不能访问enum中的非静态成员, 所实现的抽象方法所能实现的方法也是有限的,

这些方法只能是常量相关的

下面是一个enum反编译后的结果

abstract class enumerated.LikeClasses extends java.lang.Enum<enumerated.LikeClasses> {
  public static final enumerated.LikeClasses WINKEN;
  public static final enumerated.LikeClasses BLINKEN;
  public static final enumerated.LikeClasses NOD;
  static {};
  abstract void behavior();
  public static enumerated.LikeClasses[] values();
  public static enumerated.LikeClasses valueOf(java.lang.String);
  enumerated.LikeClasses(java.lang.String, int, enumerated.LikeClasses);
}

枚举中实例的方法, 也可以覆盖掉enum中已有的方法

使用enum职责链

职责链设计模式是为了解决一个问题, 把不同的解决方案放到一起形成一个职责链, 当有问题的请求来时, 逐一执行链上每一环, 直

到解决问题

下面是一个邮局处理信件的例子

//每一个Mail对象代表一封待解决的邮件

class Mail {

    //这每一个enum代表一种对信件处理的方式, 把它们串起来就是一个职责链

    //每一次尝试都可以看作一个策略, 只有当策略返回YES, OK表示解决时, 完成职责链
    enum GeneralDelivery {YES,NO1,NO2,NO3,NO4,NO5}
    enum Scannability {UNSCANNABLE,YES1,YES2,YES3,YES4}
    enum Readability {ILLEGIBLE,YES1,YES2,YES3,YES4}
    enum Address {INCORRECT,OK1,OK2,OK3,OK4,OK5,OK6}
    enum ReturnAddress {MISSING,OK1,OK2,OK3,OK4,OK5}
    GeneralDelivery generalDelivery;
    Scannability scannability;
    Readability readability;
    Address address;
    ReturnAddress returnAddress;
    static long counter = 0;
    long id = counter++;
    public String toString() { return "Main " + id; }
    public String details() {
        return toString() + 
            ", General Delivery: " + generalDelivery + 
            ", Address Scannability: " + scannability + 
            ", Address Readability: " + readability +
            ", Address Address: " + address +
            ", Return address: " + returnAddress;
    }

    //随机产生一个Mail对象, 里面为每一种enum随机分配一个实例
    public static Mail randomMail() {
        Mail m = new Mail();
        m.generalDelivery = Enums.random(GeneralDelivery.class);
        m.scannability = Enums.random(Scannability.class);
        m.readability = Enums.random(Readability.class);
        m.address = Enums.random(Address.class);
        m.returnAddress = Enums.random(ReturnAddress.class);
        return m;
    }

    //Mail的迭代器, 每次迭代产生是上面的随机邮件
    public static Iterable<Mail> generator(final int count) {
        return new Iterable<Mail>() {
            int n = count;
            public Iterator<Mail> iterator() {
                return new Iterator<Mail>() {
                    public boolean hasNext() { return n-- > 0; }
                    public Mail next() { return randomMail(); }
                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }
}
public class PostOffice {

    //用MailHandler进行每个实例的尝试, 当有一种实例返回成功的结果, 就返回true, 表示邮件被成功解决
    enum MailHandler {
        GENERAL_DELIVERY {
            boolean handle(Mail m) {
                switch(m.generalDelivery) {
                    case YES:
                    print("Using general delivery for " + m);
                    return true;
                    default: 
                    return false;
                }
            }
        },
        MACHINE_SCAN {
            boolean handle(Mail m) {
                switch(m.scannability) {
                    case UNSCANNABLE: return false;
                    default: {
                        switch (m.address) {
                            case INCORRECT: return false;
                            default: 
                                print("Delivering " + m + " automatically");
                            return true;
                        }
                    }
                }
            }
        },
        VISUAL_INSPECTION {
            boolean handle(Mail m) {
                switch(m.readability) {
                    case ILLEGIBLE: return false;
                    default: {
                        switch (m.address) {
                            case INCORRECT: return false;
                            default: 
                                print("Delivering " + m + " normally");
                            return true;
                        }
                    }
                }
            }
        },
        RETURN_TO_SENDER {
            boolean handle(Mail m) {
                switch(m.returnAddress) {
                    case MISSING: return false;
                    default: {
                        switch (m.address) {
                            case INCORRECT: return false;
                            default: 
                                print("Returning " + m + " to sender");
                            return true;
                        }
                    }
                }
            }
        };
        abstract boolean handle(Mail m);
    }

    //遍历enum MailHandler的每种尝试, 里面可以调用不同的handle方法
    static void handle(Mail m) {
        for(MailHandler handler : MailHandler.values())
            if(handler.handle(m))
                return;
        print(m + " is a dead letter");
    }

    //随机产生10个Mail, 对每个Mail, 执行一次职责链
    public static void main(String[] args) throws Exception {
        for(Mail mail : Mail.generator(10)) {
            print(mail.details());
            handle(mail);
            print("********");
        }
    }
}

使用enum的状态机

下面用了一个自动售货机的例子来表示一个状态机

定义个一个输入enum, Input每个实例具有一个值, 代表钱的价值或者商品价值

//用一个enum将这些输入状态归类

enum Category {

    //不同种类的钱
    MONEY(NICKEL, DIME, QUARTER, DOLLAR),

    //不同种类的商品
    ITEM_SELECTION(TOOTHPASTE, CHIPS, SODA, SOAP),

    //结束交易
    QUIT_TRANSACTION(ABORT_TRANSACTION),

    //结束整个状态
    SHUT_DOWN(STOP);

    //每个分类实例中放置的Input实例
    private Input[] values;

    //多个参数来初始化分类实例
    Category(Input... types) { values = types; }

    //分类eumMap, key表示一个Input, value表示它所属的分类实例
    private static EnumMap<Input, Category> categories = 
        new EnumMap<Input, Category>(Input.class);
    static {

        //每个分类实例下的Input实例数组, 作为key, 分类实例作为value, 构建map
        for(Category c : Category.class.getEnumConstants()) 
            for(Input type : c.values)
                categories.put(type,c);
    }

    //根据Input实例, 返回所属的分类
    public static Category categorize(Input input) {
        return categories.get(input);
    }
}

//上面这个分类就是得到一个根据输入的实例, 得到输入类型分类的功能

//下面这个就是自动售货机的状态机
public class VendingMachine {

    //State enum, 表示当前售货机的状态, RESTING为原始状态
    private static State state = State.RESTING;

    //表示售货机中收到的钱数
    private static int amount = 0;

    //表示选择的商品
    private static Input selection = null;
    enum StateDuration { TRANSIENT; }

    //State状态enum, 为每一状态定义next()方法, 确定下一个状态, 以及售贩等操作
    enum State {

        //原始状态
        RESTING {
            void next(Input input) {

                //根据输入所属类型来进行不同操作
                switch(Category.categorize(input)) {

                    //钱, 客人给的钱, 把数额加到售货机中收到的钱中, 转为继续收钱状态
                    case MONEY: 
                         amount += input.amount();
                         state = ADDING_MONEY;
                         break;

                    //退出售货机, 转为结束状态
                    case SHUT_DOWN: 
                         state = TERMINAL;
                    default: 
                }
            }
        },

        //继续收钱状态
        ADDING_MONEY {
            void next(Input input) {
                switch(Category.categorize(input)) {

                    //继续收钱
                    case MONEY: 
                        amount += input.amount();
                        break;

                    //选择商品, 如果收的钱不够商品价格, 输出钱不够, 否则转换为商品结算状态
                    case ITEM_SELECTION:
                        selection = input;
                        if(amount < selection.amount())
                            print("Insufficient money for " + selection);
                        else state = DISPENSING;
                        break;

                    //放弃交易, 进入找钱状态
                    case QUIT_TRANSACTION:
                        state = GIVING_CHANGE;
                        break;

                    //退出售货机, 转为结束状态
                    case SHUT_DOWN: 
                        state = TERMINAL;
                    default:
                }
            }
        },

        //结算商品状态
        DISPENSING(StateDuration.TRANSIENT) { 

            //从收到的钱中扣除商品价格, 进入找钱状态
            void next() {
                print("here is your " + selection);
                amount -= selection.amount();
                state = GIVING_CHANGE;
            }
        },

       //找钱状态
        GIVING_CHANGE(StateDuration.TRANSIENT) {
            void next() {

                //收到的钱还有剩, 找钱, 并清空收到的钱, 转换为初始状态
                if(amount > 0) {
                    print("Your change: " + amount);
                    amount = 0;
                }
                state = RESTING;
            }
        },

        //结束状态
        TERMINAL {
            void output() { print("Halted"); };
        };

        //每个状态实例是否是一个暂时性状态, 如果是暂时性状态, 处理完状态后, 不需要输入, 直接跳转到下一个状态
        private boolean isTransient = false;
        State() {}

        //暂时性状态初始化
        State(StateDuration trans) {
            isTransient = true;
        }

        //非暂时性状态, 状态改变需要输入
        void next(Input input) {
            throw new RuntimeException();
        }

        //暂时性状态, 状态改变不需要输入
        void next() {
            throw new RuntimeException();
        }

       //输出售货机中收到的钱
        void output() { print("amount: "+amount); }
    }

    //根据输入自动运行售货机
    static void run(Generator<Input> gen) {

        //遇到结束状态, 推出
        while(state != State.TERMINAL) {
            Input in = gen.next();
            System.out.println("Input: " + in);

            //获取输入并根据输入执行当前状态的方法, 调转至下一状态
            state.next(in);

           //从下一状态开始连续的暂时性状态, 直接执行转换下去, 直到遇到非暂时性状态
            while(state.isTransient)
                state.next();

            //输出钱数
            state.output();
        }
    }
    public static void main(String[] args) throws Exception {

        //从文件中按";"分隔, 读取一组Input实例, 然后运行这些实例, 查看售货机的运行状态
        Generator<Input> gen = new RandomInputGenerator();
        gen = new FileInputGenerator("VendingMachingInput.txt");
        run(gen);
    }
}
class RandomInputGenerator implements Generator<Input> {
    public Input next() { return Input.randomSelection(); }
}

class FileInputGenerator implements Generator<Input> {
    private Iterator<String> input;
    public FileInputGenerator(String fileName) {
        input = new TextFile(fileName,";").iterator();
    }
    public Input next() {
        if(!input.hasNext())
            return null;
        return Enum.valueOf(Input.class, input.next().trim());
    }
}
/*
VendingMachingInput.txt
QUARTER; QUARTER; QUARTER; CHIPS;
DOLLAR; DOLLAR; TOOTHPASTE;
QUARTER; DIME; ABORT_TRANSACTION;
QUARTER; DIME; SODA;
QUARTER; DIME; NICKEL; SODA;
ABORT_TRANSACTION;
STOP;
 */

  • 多路分发

执行的操作包含了不止一个类型未知对象的操作, 要使用多路分发

两路分发, 必须要有两个方法调用, 第一个方法调用决定第一个未知类型,  第二个调用决定第二个未知类型

下面是一个石头剪刀布的两路分发

public enum Outcome {
    WIN, LOSE, DRAW
}

//Item是这几种类型的接口, 被用作多路分发

interface Item {
    Outcome compete(Item it);
    Outcome eval(Paper p);
    Outcome eval(Scissors s);
    Outcome eval(Rock r);
}
class Paper implements Item {

    //第一个方法compete()决定第一个类型, 完成第一次分发, 即发起比较的类型, 其中的参数Item是第二个类型, 

    //把发起比较的类型当作第二个类型的参数this, 放在第二个方法中
    public Outcome compete(Item it) { return it.eval(this); }

    //第二个方法eval()决定第二个类型, 完成第二次分发, 表示被比较的类型, 它的参数是在第一次分发中确定的

   //发起比较的类型, 那么可以根据具体的参数类型重载这个方法返回比较结果
    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) throws Exception {
        for(int i = 0;i < SIZE;i++)
            match(newItem(), newItem());
    }
}

这个例子没有用到enum, 而且enum是不能作为真正的类型的

下面是使用enum进行多路分发的方法

RoShamBo2.java

//这个enum的每个实例代表一种类型, 石头, 剪刀, 或布, 它们每个都存储了, 对石头, 对剪刀, 对布的胜负结果

public enum RoShamBo2 implements Competitor<RoShamBo2>{
    PAPER(DRAW, LOSE, WIN),
    SCISSORS(WIN, DRAW, LOSE),
    ROCK(LOSE, WIN, DRAW);

    //对剪刀, 对石头, 对布的结果
    private Outcome vPaper, vScissors, vRock;
    private RoShamBo2(Outcome paper, Outcome scissors, Outcome rock)  {
        this.vPaper = paper;
        this.vScissors = scissors;
        this.vRock = rock;
    }

    //去和另一个RoShamBo2实例比较, 根据参数是哪个实例, 返回this对这个实例类型的结果
    public Outcome compete(RoShamBo2 it) {
        switch(it) {
            default: 
            case PAPER: return vPaper;
            case SCISSORS: return vScissors;
            case ROCK: return vRock;
        }
    }
    public static void main(String[] args) {
        RoShamBo.play(RoShamBo2.class, 20);
    }
}

RoShamBo.java

public class RoShamBo {
    public static <T extends Competitor<T>>
    void match(T a, T b) {
        System.out.println(a + " vs. " + b + ": " + a.compete(b));
    }
    public static <T extends Enum<T> & Competitor<T>>
    void play(Class<T> rsbClass, int size) {
        for(int i = 0;i < size;i++)
            match(Enums.random(rsbClass),Enums.random(rsbClass));
    }
}

Competitor.java

//这个泛型只能存那个类本身

public interface Competitor<T extends Competitor<T>> {
    Outcome compete(T competitor);
}

下面是一个使用EnumMap实现多路分发的例子

public enum RoShamBo5 implements Competitor<RoShamBo5> {
    PAPER, SCISSORS, ROCK;

    //这里一个EnumMap, key存发起比较的实例, value是一个EnumMap, 它的key是被比较的实例, value是比较结果

   //它是一个static成员, 已经预先存储好所有类型的所有行为以及产生的所有结果
    static EnumMap<RoShamBo5,EnumMap<RoShamBo5,Outcome>> table = 
    new EnumMap<RoShamBo5,EnumMap<RoShamBo5,Outcome>>(RoShamBo5.class);
    static {
        for(RoShamBo5 it : RoShamBo5.values())
            table.put(it, new EnumMap<RoShamBo5,Outcome>(RoShamBo5.class));
        initRow(PAPER,DRAW,LOSE,WIN);
        initRow(SCISSORS,WIN,DRAW,LOSE);
        initRow(ROCK,LOSE,WIN,DRAW);
    }
    static void initRow(RoShamBo5 it, Outcome vPaper, Outcome vScissors, Outcome vRock) {
        EnumMap<RoShamBo5, Outcome> row = 
            table.get(it);
        row.put(RoShamBo5.PAPER,vPaper);
        row.put(RoShamBo5.SCISSORS,vScissors);
        row.put(RoShamBo5.ROCK,vRock);
    }

    //根据EnumMap的结果, 当前实例this作为EnumMap的第一维key被get后, 得到该类型所对应的行为信息, 完成第一次分发

   //第二次get被比较的实例it, 得到第二次分发后的信息
    public Outcome compete(RoShamBo5 it) {
        return table.get(this).get(it);
    }
    public static void main(String[] args) {
        RoShamBo.play(RoShamBo5.class, 20);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值