1. 程式人生 > >第19章 列舉型別

第19章 列舉型別

列舉型別

public enum Spiciness {
    /**
     * 具名值,列舉型別的例項,常量
     * 按照常量書寫的慣例它們都用大寫字母表示
     */
    NOT, MID, MEDIUM, HOT, FLAMING
}
import org.testng.annotations.Test;

public class SpicinessTest {

    /**
     * 在你建立enum時,編譯器會自動新增一些有用的特性
     *
     */
    @Test(enabled = false)
    public void testSimpleEnumUse() {
        Spiciness howHot = Spiciness.MEDIUM;
        // 輸出MEDIUM。 編譯器自動新增toString方法,顯示enum例項的名字
        System.out.print(howHot);
    }

    /**
     * 儘管enum看起來像是一種新的資料型別,但是這個關鍵字知識為enum生成對應的類時,產生某些編譯行為
     */
    @Test(enabled = true)
    public void testEnumOrder() {
        // static values()方法,是由編譯器新增的static方法,Enum類中並沒有values方法,按照enum常量的宣告順序,產生這些常量值構成的陣列
        for(Spiciness s : Spiciness.values()) {
            // ordinal()方法,用來表示某個特定enum常量的宣告順序
            System.out.println(s + ", ordinal " + s.ordinal());
        }
    }
}

執行結果

基本enum特性

public enum Shrubbery {
    /**
     * 建立enum時,編譯器會為你生成一個相關的類,這個類繼承自java.lang.Enum
     */
    GROUND, CRAWLING, HANGING
}
import org.testng.annotations.Test;

public class ShrubberyTest {
    @Test(enabled = true)
    public void testShrubbery() {
        for(Shrubbery s : Shrubbery.values()) {
            // ordinal()方法返回一個int值,這是每個enum例項在宣告時的次序,從0開始
            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);
            // 在enum例項上呼叫getDeclaringClass()方法,我們就能知道其所屬的enum類
            System.out.println(s.getDeclaringClass());
            // name()方法返回enum例項宣告時的名字,這與使用toString()方法效果相同
            System.out.println(s.name());
            System.out.println("----------------------");
        }
        for(String s : "HANGING CRAWLING GROUND".split(" ")) {
            /**
             * valueOf()方法根據給定的名字返回相應的enum例項,如果不存在給定名字的例項,將會丟擲異常
             * s == null, throw new NullPointerException
             * s not exist throw new IllegalArgumentException
             */
            Shrubbery shrubbery = Enum.valueOf(Shrubbery.class, s);
            System.out.println(shrubbery);
        }
    }
}

執行結果

向enum中新增新方法

public enum OzWitch {
    /** 如果你打算定義自己的方法,那麼必須在enum例項序列的最後新增一個分號
     *  Java要求你必須先定義enum例項,如果在定義enum例項之前定義了任何方法或屬性,那麼編譯時就會得到錯誤資訊
     */
    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;
    OzWitch(String description) {
        this.description = description;
    }
    public String getDescription() {
        return description;
    }
}
import org.testng.annotations.Test;

public class OzWitchTest {
    @Test
    public void test() {
        for(OzWitch witch : OzWitch.values()) {
            System.out.println(witch + ": " + witch.getDescription());
        }
    }
}

執行結果

覆蓋enum中的方法

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

    /**
     * 覆蓋enum的toString()方法
     * @return
     */
    public String toString() {
        String id = name();
        String lower = id.substring(1).toLowerCase();
        return id.charAt(0) + lower;
    }
}
import org.testng.annotations.Test;

public class SpaceShipTest {
    @Test
    public void test() {
        for(SpaceShip s : SpaceShip.values()) {
            System.out.println(s);
        }
    }
}

執行結果

switch

public class Burrito {
    Spiciness degree;
    public Burrito(Spiciness degree) {
        this.degree = degree;
    }

    /**
     * enum有一個特別實用的特性,即它可以在switch語句內使用
     */
    public void describe() {
        System.out.print("This burrito is ");
        switch (degree) {
            case NOT:
                System.out.println("not spicy at all.");
                break;
            case MID:
            case MEDIUM:
                System.out.println("a little hot.");
                break;
            case HOT:
            case FLAMING:
                default:
                    System.out.println("maybe too hot.");

        }
    }
}
import org.testng.annotations.Test;

public class BurritoTest {

    @Test(enabled = true)
    public void testDescribe() {
        Burrito
                plain = new Burrito(Spiciness.NOT),
                greenChile = new Burrito(Spiciness.MEDIUM),
                jalapeno = new Burrito(Spiciness.HOT);
        plain.describe();
        greenChile.describe();
        jalapeno.describe();

    }
}

執行結果

EnumSet

public enum AlarmPoints {
    STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,
    OFFICE4, BATHROOM, UTILITY, KITCHEN
}
import org.testng.annotations.Test;

import java.util.EnumSet;
/**
 * 使用static import 簡化enum常量的使用
 */
import static com.dmw.enumerated.AlarmPoints.*;

public class EnumSetTest {
    @Test
    public void test() {
        // Empty set,EnumSet中的元素必須來自一個enum
        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);
    }
}

執行結果

EnumMaps

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

import static com.dmw.enumerated.AlarmPoints.*;

public class EnumMaps {
    public static void main(String[] args) {
        EnumMap<AlarmPoints, Command> em = new EnumMap<>(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 alert!");
            }
        });

        for(Map.Entry<AlarmPoints, Command> e : em.entrySet()) {
            System.out.println(e.getKey() + ":");
            e.getValue().action();
        }

        try {
            em.get(UTILITY).action();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

interface Command {
    void action();
}

執行結果

常量相關方法

import java.text.DateFormat;
import java.util.Date;

/**
 * 1. Java的enum有一個非常有趣的特性,即它允許程式設計師為enum例項編寫方法,從而為每個enum例項賦予各自不同的行為
 * 2. 通過相應的enum例項,我們可以呼叫對應的方法。這通常也稱為表驅動的程式碼(table-driven code, 和命令模式有一定的相似之處)
 * 3. 每個enum元素(例如DATE_TIME)都是一個ConstantSpecificMethod的static final例項
 */
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();
}
import org.testng.annotations.Test;

public class ConstantSpecificMethodTest {
    @Test
    public void test() {
        for(ConstantSpecificMethod csm : ConstantSpecificMethod.values()) {
            System.out.println(csm.getInfo());
        }
    }
}

比匿名內部類更加簡潔高效

import java.util.EnumSet;

/**
 * 與使用匿名內部類相比較,定義常量相關方法的語法更高效、簡潔
 */
public class CarWash {
    public enum Cycle {
        UNDERBODY {
            @Override
            void action() {
                System.out.println("Spraying the underbody");
            }
        },
        WHEELWASH {
            @Override
            void action() {
                System.out.println("Washing the wheels");
            }
        },
        PREWASH {
            @Override
            void action() {
                System.out.println("Loosening the dirt");
            }
        },
        BASIC {
            @Override
            void action() {
                System.out.println("The basic wash");
            }
        },
        HOTWAX {
            @Override
            void action() {
                System.out.println("Applying hot wax");
            }
        },
        RINSE {
            @Override
            void action() {
                System.out.println("Rinsing");
            }
        },
        BLOWDRY {
            @Override
            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();
        }
    }

    @Override
    public String toString() {
        return cycles.toString();
    }

    public static void main(String[] args) {
        CarWash wash = new CarWash();
        System.out.println(wash);
        wash.washCar();
        // Order of addition is unimportant
        wash.add(Cycle.BLOWDRY);
        // Duplicates ignored
        wash.add(Cycle.BLOWDRY);
        wash.add(Cycle.RINSE);
        wash.add(Cycle.HOTWAX);
        System.out.println(wash);
        wash.washCar();
    }
}

執行結果