单例与枚举类型

来源:互联网 发布:部落冲突攻略软件 编辑:程序博客网 时间:2024/06/05 06:10

单例与枚举

在《Effective Java》中,提到创建单例的三种方法以及枚举类型的使用。

单例实现

作者首先说明Java 1.5之前的两种单例实现方法:

方法一:Singleton with public final field

// Singleton with public final field   public class Elvis {       public static final Elvis INSTANCE = new Elvis();       private Elvis() { ... }       public void leaveTheBuilding() { ... }   }

这种方法通过私有构造方法,并提供public static final属性实现单例。但其缺点是,通过反射,及AccessibleObject.setAccessible(true)方法,可以调用私有构造方法。

方法二:Singleton with static factory

// Singleton with static factorypublic class Elvis {    private static final Elvis INSTANCE = new Elvis();     private Elvis() { ... }    public static Elvis getInstance() { return INSTANCE; }    public void leaveTheBuilding() { ... }}

这种方法也是通过私有构造方法,并提供public static方法实现单例。但其缺点时反序列化后,会创建一个新的实例。为了解决这个问题,要增加readResolve方法:

// readResolve method to preserve singleton property   private Object readResolve() {        // Return the one true Elvis and let the garbage collector        // take care of the Elvis impersonator.       return INSTANCE;   }

readResolve方法用于替换从Stream流中读出的对象,确保不会反序列化出来另一个实例。

方法三:Enum实现单例

Java 1.5以后,可以使用枚举类型实现单例:

// Enum singleton - the preferred approach   public enum Elvis {       INSTANCE;       public void leaveTheBuilding() { ... }   }

只有一个元素的enum类型是实现单例最好的方法。不存在序列化、反射等影响。

上面的简单例子似乎不太清晰,到底怎么用呢?就如下面这样:

public enum MySingleton {    INSTANCE;    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public void otherMethod() {        ...    }}//调用示例MySingleton.INSTANCE.setName("ABCD");

枚举类型究竟还有哪些功能呢?

枚举类型

枚举类型的基本用法

枚举类型最基本的用法就像下面的例子:

public enum Day {    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,    THURSDAY, FRIDAY, SATURDAY }public class EnumTest {    Day day;    public EnumTest(Day day) {        this.day = day;    }    public void tellItLikeItIs() {        switch (day) {            case MONDAY:                System.out.println("Mondays are bad.");                break;            case FRIDAY:                System.out.println("Fridays are better.");                break;            case SATURDAY: case SUNDAY:                System.out.println("Weekends are best.");                break;            default:                System.out.println("Midweek days are so-so.");                break;        }    }    public static void main(String[] args) {        EnumTest firstDay = new EnumTest(Day.MONDAY);        firstDay.tellItLikeItIs();        EnumTest thirdDay = new EnumTest(Day.WEDNESDAY);        thirdDay.tellItLikeItIs();        EnumTest fifthDay = new EnumTest(Day.FRIDAY);        fifthDay.tellItLikeItIs();        EnumTest sixthDay = new EnumTest(Day.SATURDAY);        sixthDay.tellItLikeItIs();        EnumTest seventhDay = new EnumTest(Day.SUNDAY);        seventhDay.tellItLikeItIs();    }}//The output is:Mondays are bad.Midweek days are so-so.Fridays are better.Weekends are best.Weekends are best.

还可以对枚举类型遍历:

for (Day p : Day.values()) {    ...}

其它大家熟知的用法还包括:

public enum Coin {    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);    Coin(int value) {        this.value = value;    }    private final int value;    public int value() {        return value;    }}

枚举类型的高级用法

枚举常量的自引用(Self-Reference)限制

//有错误代码enum Color {    RED, GREEN, BLUE;    Color() { colorMap.put(toString(), this); }    static final Map<String,Color> colorMap =        new HashMap<String,Color>();}

上面的代码中,colorMap并未初始化,所以构造方法会出错!可以改成:

enum Color {    RED, GREEN, BLUE;    static final Map<String,Color> colorMap =        new HashMap<String,Color>();    static {        for (Color c : Color.values())            colorMap.put(c.toString(), c);    }}

Enum Constants with Class Bodies

枚举类型还能这么玩:

enum Operation {    PLUS {        double eval(double x, double y) { return x + y; }    },    MINUS {        double eval(double x, double y) { return x - y; }    },    TIMES {        double eval(double x, double y) { return x * y; }    },    DIVIDED_BY {        double eval(double x, double y) { return x / y; }    };    // Each constant supports an arithmetic operation    abstract double eval(double x, double y);    public static void main(String args[]) {        double x = Double.parseDouble(args[0]);        double y = Double.parseDouble(args[1]);        for (Operation op : Operation.values())            System.out.println(x + " " + op + " " + y +                               " = " + op.eval(x, y));    }}java Operation 2.0 4.02.0 PLUS 4.0 = 6.02.0 MINUS 4.0 = -2.02.0 TIMES 4.0 = 8.02.0 DIVIDED_BY 4.0 = 0.5
0 0
原创粉丝点击