Thinking in Java Ch19 枚举

19.1 基本enum特性

package Ch19;

import static net.mindview.util.Print.print;
import static net.mindview.util.Print.printnb;

enum Shrubbery{ GROUND, CRAWLING, HANGING }

public class EnumClass {
    public static void main(String[] args) {
        for(Shrubbery s : Shrubbery.values()){
          //ordinal()方法返回enum实例声明时的次序。
            print(s+" ordianl: "+s.ordinal());
            printnb(s.equals(Shrubbery.CRAWLING)+" ");
            print(s==Shrubbery.CRAWLING);
          //返回声明时的类
            print(s.getDeclaringClass());
          //enum实例的名字
            print(s.name());
            print("-------------------");
        }

        for(String s : "HANGING CRAWLING GROUND".split(" ")){
          //静态方法valueOf,返回enum类中给的名字的实例
            Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);
            print(shrub);
        }
    }

}
  /*GROUND ordianl: 0
false false
class Ch19.Shrubbery
GROUND
-------------------
CRAWLING ordianl: 1
true true
class Ch19.Shrubbery
CRAWLING
-------------------
HANGING ordianl: 2
false false
class Ch19.Shrubbery
HANGING
-------------------
HANGING
CRAWLING
GROUND
*/

19.1.1 将静态导入用于enum

//非静态导入
package Ch19;

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

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) {
        System.out.println(new Burrito(Spiciness.NOT));
        System.out.println(new Burrito(Spiciness.MEDIUM));
        System.out.println(new Burrito(Spiciness.HOT));
    }
}

package Ch19;

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

package Ch19;
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) {
        System.out.println(new Burrito(NOT));
        System.out.println(new Burrito(MEDIUM));
        System.out.println(new Burrito(HOT));
    }
}
/*Burrito is NOT
Burrito is MEDIUM
Burrito is HOT*/

19.2 向enum中添加新方法

不能继承enum。enum和class是同级关键词。

19.3 switch语句中的enum

package Ch19;

import static tools.Print.print;

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 t = new TrafficLight();
        for(int i = 0; i<7; i++) {
            print(t);
            t.change();
        }
    }
}

19.4 values的神秘之处

19.5 实现而非继承

package Ch19;

import Ch15.Generator;

import java.util.*;

import Ch7.Cartoon;
import net.mindview.util.*;

enum CartoonCharacter implements Generator<CartoonCharacter>{
    SLAPPY,SPANKY,PUNCHY,SILLY,BOUNCY,NUTTY,BOB;
    private Random rand = new Random(47);
    public CartoonCharacter next() {
        return values()[rand.nextInt(values().length)];
        }
}
public class EnumImplementation {
    public static<T> void printNext(Generator<T> rg){
        System.out.print(rg.next()+". ");
    }

    public static void main(String[] args) {
        CartoonCharacter cc = CartoonCharacter.BOB;
        for(int i=0; i<10; i++)
            printNext(cc);
    }
}
/*BOB. PUNCHY. BOB. SPANKY. NUTTY. PUNCHY. SLAPPY. NUTTY. NUTTY. SLAPPY. */

19.6 随机选取

package Ch19;

import java.util.Random;

public class Enums {
    private static Random rand = new Random(47);
  // <T extends Enum<T>>表示T是enum的一个实例
    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)];
    }
}

package Ch19;

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<3; i++)
            System.out.print(Enums.random(Activity.class)+" ");
    }
}

19.7 使用接口组织枚举

package Ch19;
    public interface Food {
        enum Appetizer implements Food {
            sALAD, SOUP, SPRING_ROLL5;
        }
        enum MainCourse implements Food {
            LASAGNE,BURRITO;
        }
    }
package Ch19;

public class TypeOfFood {
    public static void main(String[] args) {
        Food food = Food.Appetizer.sALAD;
        food = Food.MainCourse.LASAGNE;
    }
}
package Ch19;

public enum Course { APPETIZER(Food.Appetizer.class),MAINCOURESE(Food.MainCourse.class),COFFEE(Food.Coffee.class);
    private Food[] values;
    //构造器
    private Course(Class<? extends Food> kind) {
      // 方法返回枚举的实例
        values = kind.getEnumConstants();
    }

    public Food randomSelection(){
      //随机返回数组中元素
        return Enums.random(values);
    }
}

public class Meal {
    public static void main(String[] args) {
        for(int i=0; i<5; i++){
            for(Course course : Course.values()){
                Food food = course.randomSelection();
                System.out.println(food);
            }
            System.out.println("---");
        }
    }
}
/*
SPRING_ROLL5
VINDALOO
HERB_TEA
---
SPRING_ROLL5
BURRITO
ESPRESSO
---
SOUP
PAD_THAT
TEA
---
SOUP
LASAGNE
TEA
---
sALAD
BURRITO
LATTE
---
*/


/*将一个enum嵌套在另外一个enum内*/
package Ch19;
import net.mindview.util.*;

public enum SecurityCategory {
    STOCK(Security.Stock.class), BOND(Security.Bond.class);
    Security[] values;
    //构造器
    SecurityCategory(Class<? extends Security> kind) {
        values = kind.getEnumConstants();
    }
    //将Stock和Bond组织成公共类型。
    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+": "+category.randomSelection());
        }
    }
}
/*BOND: MUNICIPAL
BOND: MUNICIPAL
STOCK: MARGIN
STOCK: MARGIN
BOND: JUNK
STOCK: SHORT
STOCK: LONG
STOCK: LONG
BOND: MUNICIPAL
BOND: JUNK
*/

19.8 使用EnumSet替代标志

EnumSet的基础是long,一个long有64位,而一个enum实例只需一位表示存在。最多使用不超过64个元素的enum(实际可以)。

package Ch19;

import java.util.*;
import static Ch19.AlarmPoints.*;
import static net.mindview.util.Print.print;

public class EnumSets {
    public static void main(String[] args) {
        EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class);
        points.add(BATHROOM);
        print(points);
        points.addAll(EnumSet.of(STAIR1,STAIR2,KITCHEN));
        print(points);
        points = EnumSet.allOf(AlarmPoints.class);
        print(points);
        points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
        print(points);
        points = EnumSet.complementOf(points);
        print(points);
    }
}
/*[BATHROOM]
[STAIR1, STAIR2, BATHROOM, KITCHEN]
[STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN]
[LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY]
[STAIR1, STAIR2, KITCHEN]*/

19.9 使用EnumMap

package Ch19;

import java.util.*;


import static Ch19.AlarmPoints.*;
import static net.mindview.util.Print.*;

interface Command {void action();}

public class EnumMaps {
    public static void main(String[] args) {
      //EnumMap要求Key必须来自一个enum,EnumMao内部是用数组实现。
        EnumMap<AlarmPoints,Command> em = new EnumMap<>(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).action();
        }catch (Exception e){
            print(e);
        }
    }
}
/*BATHROOM: Bathroom alert!
KITCHEN: Kitchen fire!
java.lang.NullPointerException*/
抛出的空指针异常源于enum实例作为一个键总是存在,默认值为null

19.10 常量相关方法

enum允许为enum实例编写方法。需要你为enum定义一个或多个abstract方法,如何为每个enum实例实现该抽象方法。

package Ch19;
// table-driven-code 通过相应的enum实例,可以调用其上的方法。
import java.text.DateFormat;
import java.util.Date;

public enum ConstantSpecificMethod {
    DATE_TIME {
        String getInfo() {
            return DateFormat.getDateInstance().format(new Date());
        }
    },

    CLASSPATH{
      String getInfo(){
          return System.getenv("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());
    }

}
/*2017-11-17
F:\TIJ4\code;
1.8.0_131*/

package Ch19;

import java.util.EnumSet;

public class CarWash {
    public enum Cycle {
        UNDERBODY{
            void action(){
                System.out.println("Spraying");
            }
        },
        WHEELWASH{
            void action(){
                System.out.println("Washing");
            }
        },
        PREWASH{
            void action(){
                System.out.println("Loosening");
            }
        },
        BASIC{
            void action(){
                System.out.println("The basic wash");
            }
        },
        HOTWAX{
            void action(){
                System.out.println("Applying");
            }
        },
        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();
    }
    //CarWash的toString调用了cyclyes的toString方法。
    public String toString(){return  cycles.toString();}

    public static void main(String[] args) {
        CarWash wash = new CarWash();
        System.out.println(wash);
        wash.washCar();
        wash.add(Cycle.BLOWDRY);
      //Set重复调用被忽略
        wash.add(Cycle.BLOWDRY);
        wash.add(Cycle.RINSE);
        wash.add(Cycle.HOTWAX);
        System.out.println(wash);
        wash.washCar();
    }
}
/*[BASIC, RINSE]
The basic wash
Rinsing
[BASIC, HOTWAX, RINSE, BLOWDRY]
The basic wash
Applying
Rinsing
Blowing dry*/

19.10.1 使用enum的职责链(chain of Responsibility)

职责链,程序员以多种不同方法来解决一个问题,然后把他们链接在一起。当一个请求到来时,它遍历这个链,直到链中某个解决方法能够处理该请求。

package Ch19;
import java.util.Iterator;
//定义邮件
class Mail {
  //定义邮件可以确认的信息属性。
    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}
  // Mail的属性,留待初始化。
    GeneralDelivery generalDelivery;
    Scannability scannability;
    Readability readability;
    Address address;
    ReturnAddress returnAddress;
    static long counter = 0;
    long id = counter++;
    public String toString(){return "Mail "+id;}
  //打印初始化的信息。
    public String details(){
        return toString() +
                ", General Delivery: "+generalDelivery
                +", Address Scanability: "+scannability
                +", Address Readablity: "+readability
                +", Address Address: "+address
                +", Return address: "+returnAddress;
    }
    //不是类名的初始化函数。利用Enums的random函数。
    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;
    }
    //generato对象生成器。调用上面random函数。
    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 {
  //将不同的邮件的处理方法组织成职责链。
    enum MailHandler {
        GENERAL_DELIVERY {
            boolean handle(Mail m){
                switch(m.generalDelivery) {
                    case YES:
                        System.out.println("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:
                                System.out.println("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:
                                System.out.println("Delivering "+m+" normally");
                                return true;
                        }
                }
            }
        },
        RETURN_TO_SENDER {
            boolean handle(Mail m) {
                switch (m.returnAddress){
                    case MISSING : return false;
                    default:
                        System.out.println("Returning "+m+" to sender");
                        return true;
                }
            }
        };

        abstract boolean handle(Mail m);
    }
    //对于每一封邮件,按照职责链匹配职责。
    static void handle(Mail m) {
        for(MailHandler handler : MailHandler.values())
            if(handler.handle(m))
                return;
        System.out.println(m+" is a dead letter");
    }
    //测试
    public static void main(String[] args) {
        for(Mail mail : Mail.generator(3)) {
            System.out.println(mail.details());
            handle(mail);
            System.out.println("*****");
        }
    }

}
/*Mail 0, General Delivery: NO2, Address Scanability: UNSCANNABLE, Address Readablity: YES3, Address Address: OK1, Return address: OK1
Delivering Mail 0 normally
*****
Mail 1, General Delivery: NO5, Address Scanability: YES3, Address Readablity: ILLEGIBLE, Address Address: OK5, Return address: OK1
Delivering Mail 1 automatically
*****
Mail 2, General Delivery: YES, Address Scanability: YES3, Address Readablity: YES1, Address Address: OK1, Return address: OK5
Using general delivery for Mail 2
*****
*/

19.10.2 使用enum状态机??

枚举类型非常适合用来创建状态机

19.11 多路分发

Java只支持单路分发–也就是说,如果要执行的操作包含了不止一个类型未知的对象时,那么Java的动态绑定机制只能处理其中一个的类型。你必须自己判断其他的类型,从而实现自己的动态绑定行为。

解决方法–多路分发,必须为每个类型提供一个实际的方法调用。

package Ch19;
//所谓类型未知,常指一个基类有很多导出类,调用方法时,不知具体导出类型,只知道基类。
//变量被声明时的类型叫做变量的静态类型(Static Type) 又叫明显类型(Apparent Type)。变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type)。
import static Ch19.Outcome.*;
import java.util.*;

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

class Paper implements Item {
  //compete方法解决调用方法的动态绑定,实现第一次分发。内部再调用eval方法,
  //通过参数的重载实现第二次分发

  /*
  方法重载是静态分派(多发)(java中静态绑定),方法重写是动态分派(单发)(java中通过动态绑定实现)。
  如果想要实单发,则compete(par)调用时,par必须是实际类型,将compete重载为三个函数。且同时要求nextitem重写为3个函数,以产生明确的导出类类型。

 a.compete(b)
 a是item,b是item。这样提供一个item接口,避免重载上述compete和nextItem方法。
 先根据a的实际类型选择具体compete方法(动态)。 然后调用eval(b),(eval重载为三个导出类类型),在调用eval的时候就必须根据b的具体类型来调用(静态)。
  */
    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 RoShaBo1 {
    static final int SIZE = 5;
    private static Random rand = new Random(47);
    public static Item nextItem(){
        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(nextItem(),nextItem());
    }
}
/*Rock vs. Rock: DRAW
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Scissors vs. Paper: WIN*/

19.11.1 使用enum分发

““java
package Ch19;

import static Ch19.Outcome.*;

public enum RoshamBo2
implements Competitor
{
PAPER(DRAW,LOSE, WIN), SCISSORS(LOSE,WIN,DRAW), ROCK(LOSE,WIN,DRAW);

private Outcome vPAPER;
private Outcome vSCISSORS;
private Outcome vROCK;

RoshamBo2(Outcome paper, Outcome scissors, Outcome rock){
    this.vSCISSORS = scissors;
    this.vPAPER = paper;
    this.vROCK = rock;
}
public Outcome compete(RoshamBo2 it)
{
    switch (it) {
        default:
        case PAPER:
            return this.vROCK;
        case SCISSORS:
            return this.vPAPER;
        case ROCK:
            return this.vSCISSORS;
    }
}

public static void main(String[] args)
{
    RoShamBo.play(RoshamBo2.class, 5);
}

}
/*ROCK vs. ROCK: WIN
SCISSORS vs. ROCK: WIN
SCISSORS vs. ROCK: WIN
SCISSORS vs. ROCK: WIN
PAPER vs. SCISSORS: DRAW
*/
““

19.11.3 使用EnumMap分发

package Ch19;

import java.util.EnumMap;
import static Ch19.Outcome.*;

public enum RoShamBo5 implements Competitor<RoShamBo5>{
    PAPER,SCISSORS,ROCK;
  //EnumMap中定义了final static keyType变量,必须在构造器中初始化。
  //所以有RoShamBo.class
    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 = RoShamBo5.table.get(it);
        row.put(RoShamBo5.PAPER,vPAPER);
        row.put(RoShamBo5.SCISSORS,vSCISSORS);
        row.put(RoShamBo5.ROCK,vROCK);
    }

    public Outcome compete(RoShamBo5 it){
        return table.get(this).get(it);
    }

    public static void main(String[] args) {
        RoShamBo.play(RoShamBo5.class,5);
    }

}//本质也是多维数组
/*ROCK vs. ROCK: DRAW
SCISSORS vs. ROCK: LOSE
SCISSORS vs. ROCK: LOSE
SCISSORS vs. ROCK: LOSE
PAPER vs. SCISSORS: LOSE*/

19.11.4 使用二维数组

数组不安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值