• 枚举


    调用 enum 的 values() 方法,可以遍历 enum 实例 .values() 方法返回 enum 实例的数组,而且该数组中的元素严格保持其在 enum 中声明时的顺序,因此你可以在循环中使用 values() 返回的数组。

    // enums/EnumClass.java
    // Capabilities of the Enum class
    enum Shrubbery { GROUND, CRAWLING, HANGING }
    public class EnumClass {
        public static void main(String[] args) {
            for(Shrubbery s : Shrubbery.values()) {
                System.out.println(
                        s + " ordinal: " + s.ordinal());
                System.out.print(
                        s.compareTo(Shrubbery.CRAWLING) + " ");
                System.out.print(
                        s.equals(Shrubbery.CRAWLING) + " ");
                System.out.println(s == Shrubbery.CRAWLING);
                System.out.println(s.getDeclaringClass());
                System.out.println(s.name());
                System.out.println("********************");
            }
    // Produce an enum value from a String name:
            for(String s :
                    "HANGING CRAWLING GROUND".split(" ")) {
                Shrubbery shrub =
                        Enum.valueOf(Shrubbery.class, s);
                System.out.println(shrub);
            }
        }
    }

    输出

    GROUND ordinal: 0
    -1 false false
    class Shrubbery
    GROUND
    ********************
    CRAWLING ordinal: 1
    0 true true
    class Shrubbery
    CRAWLING
    ********************
    HANGING ordinal: 2
    1 false false
    class Shrubbery
    HANGING
    ********************
    HANGING
    CRAWLING
    GROUND

    方法添加的enum类,这主要用于自定义

    // enums/OzWitch.java
    // The witches in the land of Oz
    public enum OzWitch {
        // Instances must be defined first, before methods:
        WEST("Miss Gulch, aka the Wicked Witch of the West"),
        NORTH("Glinda, the Good Witch of the North"),
        EAST("Wicked Witch of the East, wearer of the Ruby " +
                "Slippers, crushed by Dorothy's house"),
        SOUTH("Good by inference, but missing");
        private String description;
        // Constructor must be package or private access:
        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 + ": " + witch.getDescription());
        }
    }
    WEST: Miss Gulch, aka the Wicked Witch of the West
    NORTH: Glinda, the Good Witch of the North
    EAST: Wicked Witch of the East, wearer of the Ruby
    Slippers, crushed by Dorothy's house
    SOUTH: Good by inference, but missing

    覆盖enum

    // enums/SpaceShip.java
    import java.util.stream.*;
    public enum SpaceShip {
        SCOUT, CARGO, TRANSPORT,
        CRUISER, BATTLESHIP, MOTHERSHIP;
        @Override
        public String toString() {
            String id = name();
            String lower = id.substring(1).toLowerCase();
            return id.charAt(0) + lower;
        }
        public static void main(String[] args) {
            Stream.of(values())
                    .forEach(System.out::println);
        }
    }

    输出

    Scout
    Cargo
    Transport
    Cruiser
    Battleship
    Mothership

    enum和switch

    // enums/TrafficLight.java
    // Enums in switch statements
    // Define an enum type:
    enum Signal { GREEN, YELLOW, RED, }
    
    public class TrafficLight {
        Signal color = Signal.RED;
        public void change() {
            switch(color) {
               // Note you don't have to say Signal.RED
                // in the case statement:
                case RED: color = Signal.GREEN;
                    break;
                case GREEN: color = Signal.YELLOW;
                    break;
                case YELLOW: color = Signal.RED;
                    break;
            }
        }
        @Override
        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++) {
                System.out.println(t);
                t.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

    编译器并没有抱怨 switch 中没有 default 语句,但这并不是因为每一个 Signal 都有对应的 case 语句。如果你注释掉其中的某个 case 语句,编译器同样不会抱怨什么。这意味着,你必须确保自己覆盖了所有的分支。但是,如果在 case 语句中调用 return,那么编译器就会抱怨缺少 default 语句了。这与是否覆盖了 enum 的所有实例无关。

    如果你将 enum 实例向上转型为 Enum,那么 values() 方法就不可访问了。

    // enums/UpcastEnum.java
    // No values() method if you upcast an enum
    enum Search { HITHER, YON }
    public class UpcastEnum {
        public static void main(String[] args) {
            Search[] vals = Search.values();
            Enum e = Search.HITHER; // Upcast
    // e.values(); // No values() in Enum
            for(Enum en : e.getClass().getEnumConstants())
                System.out.println(en);
        }
    }

    输出

    HITHER
    YON

    因为 getEnumConstants() 是 Class 上的方法,所以你甚至可以对不是枚举的类调用此方法:

    // enums/NonEnum.java
    public class NonEnum {
        public static void main(String[] args) {
            Class<Integer> intClass = Integer.class;
            try {
                for(Object en : intClass.getEnumConstants())
                    System.out.println(en);
            } catch(Exception e) {
                System.out.println("Expected: " + e);
            }
        }
    }

    输出

    Expected: java.lang.NullPointerException

    ENUM类不可继承可以实现

    enum NotPossible extends Pet { ... // Won't work

    随机选择

    // onjava/Enums.java
    package onjava;
    import java.util.*;
    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)];
        }
    }
    // enums/RandomTest.java
    import onjava.*;
    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.print(
                        Enums.random(Activity.class) + " ");
        }
    }

    输出

    STANDING FLYING RUNNING STANDING RUNNING STANDING LYING
    DODGING SITTING RUNNING HOPPING HOPPING HOPPING RUNNING
    STANDING LYING FALLING RUNNING FLYING LYING

    使用接口组织枚举

    // enums/menu/Food.java
    // Subcategorization of enums within interfaces
    package enums.menu;
    public interface Food {
        enum Appetizer implements Food {
            SALAD, SOUP, SPRING_ROLLS;
        }
        enum MainCourse implements Food {
            LASAGNE, BURRITO, PAD_THAI,
            LENTILS, HUMMOUS, VINDALOO;
        }
        enum Dessert implements Food {
            TIRAMISU, GELATO, BLACK_FOREST_CAKE,
            FRUIT, CREME_CARAMEL;
        }
        enum Coffee implements Food {
            BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
            LATTE, CAPPUCCINO, TEA, HERB_TEA;
        }
    }
    // enums/menu/TypeOfFood.java
    // {java enums.menu.TypeOfFood}
    package enums.menu;
    import static enums.menu.Food.*;
    public class TypeOfFood {
        public static void main(String[] args) {
            Food food = Appetizer.SALAD;
            food = MainCourse.LASAGNE;
            food = Dessert.GELATO;
            food = Coffee.CAPPUCCINO;
        }
    }

    EnumSet

    // enums/AlarmPoints.java
    package enums;
    public enum AlarmPoints {
        STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,
        OFFICE4, BATHROOM, UTILITY, KITCHEN
    }
    // enums/EnumSets.java
    // Operations on EnumSets
    // {java enums.EnumSets}
    package enums;
    import java.util.*;
    import static enums.AlarmPoints.*;
    public class EnumSets {
        public static void main(String[] args) {
            EnumSet<AlarmPoints> points =
                    EnumSet.noneOf(AlarmPoints.class); // Empty
            points.add(BATHROOM);
            System.out.println(points);
            points.addAll(
                    EnumSet.of(STAIR1, STAIR2, KITCHEN));
            System.out.println(points);
            points = EnumSet.allOf(AlarmPoints.class);
            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);
        }
    }

    输出

    [BATHROOM]
    [STAIR1, STAIR2, BATHROOM, KITCHEN]
    [LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM,
    UTILITY]
    [LOBBY, BATHROOM, UTILITY]
    [STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4,
    KITCHEN]

    EnumSet 的基础是 long,一个 long 值有 64 位,而一个 enum 实例只需一位 bit 表示其是否存在。 也就是说,在不超过一个 long 的表达能力的情况下,你的 EnumSet 可以应用于最多不超过 64 个元素的 enum。如果 enum 超过了 64 个元素会发生什么呢?

    // enums/BigEnumSet.java
    import java.util.*;
    public class BigEnumSet {
        enum Big { A0, A1, A2, A3, A4, A5, A6, A7, A8, A9,
            A10, A11, A12, A13, A14, A15, A16, A17, A18, A19,
            A20, A21, A22, A23, A24, A25, A26, A27, A28, A29,
            A30, A31, A32, A33, A34, A35, A36, A37, A38, A39,
            A40, A41, A42, A43, A44, A45, A46, A47, A48, A49,
            A50, A51, A52, A53, A54, A55, A56, A57, A58, A59,
            A60, A61, A62, A63, A64, A65, A66, A67, A68, A69,
            A70, A71, A72, A73, A74, A75 }
        public static void main(String[] args) {
            EnumSet<Big> bigEnumSet = EnumSet.allOf(Big.class);
            System.out.println(bigEnumSet);
        }
    }

    输出

    [A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12,
    A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23,
    A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34,
    A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45,
    A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56,
    A57, A58, A59, A60, A61, A62, A63, A64, A65, A66, A67,
    A68, A69, A70, A71, A72, A73, A74, A75]

    显然,EnumSet 可以应用于多过 64 个元素的 enum,所以我猜测,Enum 会在必要的时候增加一个 long。

    EnumMap

    // enums/EnumMaps.java
    // Basics of EnumMaps
    // {java enums.EnumMaps}
    package enums;
    import java.util.*;
    import static enums.AlarmPoints.*;
    interface Command { void action(); }
    public class EnumMaps {
        public static void main(String[] args) {
            EnumMap<AlarmPoints,Command> em =
                    new EnumMap<>(AlarmPoints.class);
            em.put(KITCHEN,
                    () -> System.out.println("Kitchen fire!"));
            em.put(BATHROOM,
                    () -> System.out.println("Bathroom alert!"));
            for(Map.Entry<AlarmPoints,Command> e:
                    em.entrySet()) {
                System.out.print(e.getKey() + ": ");
                e.getValue().action();
            }
            try { // If there's no value for a particular key:
                em.get(UTILITY).action();
            } catch(Exception e) {
                System.out.println("Expected: " + e);
            }
        }
    }

    输出

    BATHROOM: Bathroom alert!
    KITCHEN: Kitchen fire!
    Expected: java.lang.NullPointerException

    常量特定方法

    Java 的 enum 有一个非常有趣的特性,即它允许程序员为 enum 实例编写方法,从而为每个 enum 实例赋予各自不同的行为。要实现常量相关的方法,你需要为 enum 定义一个或多个 abstract 方法,然后为每个 enum 实例实现该抽象方法。参考下面的例子:

    // enums/ConstantSpecificMethod.java
    import java.util.*;
    import java.text.*;
    public enum ConstantSpecificMethod {
        DATE_TIME {
            @Override
            String getInfo() {
                return
                        DateFormat.getDateInstance()
                                .format(new Date());
            }
        },
        CLASSPATH {
            @Override
            String getInfo() {
                return System.getenv("CLASSPATH");
            }
        },
        VERSION {
            @Override
            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());
        }
    }

    输出

    May 9, 2017
    C:UsersBruceDocumentsGitHubon-
    javaExtractedExamples\gradlewrappergradle-
    wrapper.jar
    1.8.0_112

    enum也是类,是很奇怪的。

    // enums/OverrideConstantSpecific.java
    public enum OverrideConstantSpecific {
        NUT, BOLT,
        WASHER {
            @Override
            void f() {
                System.out.println("Overridden method");
            }
        };
        void f() {
            System.out.println("default behavior");
        }
        public static void main(String[] args) {
            for(OverrideConstantSpecific ocs : values()) {
                System.out.print(ocs + ": ");
                ocs.f();
            }
        }
    }

    输出

    NUT: default behavior
    BOLT: default behavior
    WASHER: Overridden method

    enum状态机

    // enums/Input.java
    import java.util.*;
    public enum Input {
        NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100),
        TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50),
        ABORT_TRANSACTION {
            @Override
            public int amount() { // Disallow
                throw new RuntimeException("ABORT.amount()");
            }
        },
        STOP { // This must be the last instance.
            @Override
            public int amount() { // Disallow
                throw new RuntimeException("SHUT_DOWN.amount()");
            }
        };
        int value; // In cents
        Input(int value) { this.value = value; }
        Input() {}
        int amount() { return value; }; // In cents
        static Random rand = new Random(47);
        public static Input randomSelection() {
            // Don't include STOP:
            return values()[rand.nextInt(values().length - 1)];
        }
    }

    多路分发

    当你要处理多种交互类型时,程序可能会变得相当杂乱。举例来说,如果一个系统要分析和执行数学表达式。我们可能会声明 Number.plus(Number),Number.multiple(Number) 等等,其中 Number 是各种数字对象的超类。然而,当你声明 a.plus(b) 时,你并不知道 a 或 b 的确切类型,那你如何能让它们正确地交互呢?

    你可能从未思考过这个问题的答案.Java 只支持单路分发。也就是说,如果要执行的操作包含了不止一个类型未知的对象时,那么 Java 的动态绑定机制只能处理其中一个的类型。这就无法解决我们上面提到的问题。所以,你必须自己来判定其他的类型,从而实现自己的动态线定行为。

    解决上面问题的办法就是多路分发(在那个例子中,只有两个分发,一般称之为两路分发).多态只能发生在方法调用时,所以,如果你想使用两路分发,那么就必须有两个方法调用:第一个方法调用决定第一个未知类型,第二个方法调用决定第二个未知的类型。要利用多路分发,程序员必须为每一个类型提供一个实际的方法调用,如果你要处理两个不同的类型体系,就需要为每个类型体系执行一个方法调用。一般而言,程序员需要有设定好的某种配置,以便一个方法调用能够引出更多的方法调用,从而能够在这个过程中处理多种类型。为了达到这种效果,我们需要与多个方法一同工作:因为每个分发都需要一个方法调用。在下面的例子中(实现了 “石头、剪刀、布”游戏,也称为 RoShamBo)对应的方法是 compete() 和 eval(),二者都是同一个类型的成员,它们可以产生三种 Outcome 实例中的一个作为结果:

    // enums/Outcome.java
    package enums;
    public enum Outcome { WIN, LOSE, DRAW }
    // enums/RoShamBo1.java
    // Demonstration of multiple dispatching
    // {java enums.RoShamBo1}
    package enums;
            import java.util.*;
            import static enums.Outcome.*;
    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; }
        @Override
        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; }
        @Override
        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; }
        @Override
        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());
        }
    }

    输出

    Rock vs. Rock: DRAW
    Paper vs. Rock: WIN
    Paper vs. Rock: WIN
    Paper vs. Rock: WIN
    Scissors vs. Paper: WIN
    Scissors vs. Scissors: DRAW
    Scissors vs. Paper: WIN
    Rock vs. Paper: LOSE
    Paper vs. Paper: DRAW
    Rock vs. Paper: LOSE
    Paper vs. Scissors: LOSE
    Paper vs. Scissors: LOSE
    Rock vs. Scissors: WIN
    Rock vs. Paper: LOSE
    Paper vs. Rock: WIN
    Scissors vs. Paper: WIN
    Paper vs. Scissors: LOSE
    Paper vs. Scissors: LOSE
    Paper vs. Scissors: LOSE
    Paper vs. Scissors: LOSE
    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    Resharper让我们的asp.net开发效率提高三分之一
    做linux运维工程师,必须要掌握以下几个工具
    NodeJs端口被占用的情况
    Angel工作室EasyUI通用权限管理框架正式发布
    如何采用easyui tree编写简单角色权限代码
    C# Session添加、删除封装类
    Windows8.1下安装NoSQL-- mongodb安装使用
    redhat6.4安装MySQL-server-5.5.28-1.linux2.6.x86_64.rpm
    linux下安装MySQL出错file /usr/share/mysql/charsets/latin2.xml from install of MySQL-......
    Windows8.1系统下让VS2012编译运行IIS Express 64位 调试器
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12013098.html
Copyright © 2020-2023  润新知