9

您可能知道,有些人使用 Enum 为 1 个实例声明单例,因为 JVM 保证总会有一个没有并发问题需要处理的单个实例...

那么具有多个实例的 Enum 呢?我们可以说像 Enum 这样的东西是一种共享公共接口的有序单例吗?为什么?

public enum EnumPriceType {

    WITH_TAXES {
        @Override
        public float getPrice(float input) {
            return input*1.20f;
        }
        public String getFormattedPrice(float input) {
            return input*1.20f + " €";
        }
        },

    WITHOUT_TAXES {
        @Override
        public float getPrice(float input) {
            return input;
        }
    },
    ;

    public abstract float getPrice(float input);

    public static void main(String[] args) {
        WITH_TAXES.getFormattedPrice(33f);
    }

}

在这段代码中为什么这不起作用: WITH_TAXES.getFormattedPrice(33f); 如果不通过公共接口就不能调用公共方法,那么声明公共方法有什么好处?我想这就是为什么我看不到任何语法能够仅为枚举的一个实例声明一个接口。


编辑:

似乎枚举实例是一种特殊的匿名类。因此,我理解为什么您不能调用该方法。

我的问题有点相关:为什么匿名类不能实现接口(除了它可能已经实现的接口!)

我完全理解为什么我们不能这样做:

Vehicle veh = new Vehicle() {
    public String getName() {
        return "toto";
    }
};
veh.getName();

(这里的 getName 不是覆盖)

为什么我不明白为什么我们不能用匿名类做到这一点:

Runnable veh = new Vehicle() implements Runnable {
    @Override
    public void run() {
        System.out.println("i run!");
    }
};
veh.run();

或者会导致同样事情的事情。想一想:如果您不使用匿名类,您绝对可以扩展 Vehicle 类,然后让该子类实现您想要的任何其他接口......

我很确定,如果可能的话,我们将能够以类型安全的方式调用 WITH_TAXES.getFormattedPrice(33f),因为 WITH_TAXES 不是真正的 EnumPriceType,但它只是 EnumPriceType 的子类,具有自己的接口,并且通过使用硬编码的 WITH_TAXES 调用 WITH_TAXES.getFormattedPrice(33f),您可以在编译时知道您正在调用哪个 EnumPriceType 子项。

所以我的问题是:有什么理由说明这是不可能的吗?还是只是还没有完成?

4

3 回答 3

11

你的枚举相当于下面的普通类(事实上,这几乎就是编译器把它变成的):

public abstract class EnumPriceType {

    public static final EnumPriceType WITH_TAXES = new EnumPriceType() {
        //getPrice() {...}
        //getFormattedPrice() {...}
    };

    public static final EnumPriceType WITHOUT_TAXES = new EnumPriceType() {
        //getPrice() {...}
    };

    public abstract float getPrice(float input);

    public static void main(String[] args) {
        WITH_TAXES.getFormattedPrice(33f);
    }
}

getFormattedPrice()方法在抽象类型上不可用,因此无法从 main 方法调用。考虑如果重写 main 方法以使用局部变量会发生什么:

public static void main(String[] args) {
    EnumPriceType foo = EnumPriceType.WITH_TAXES;
    foo.getFormattedPrice(33f);
}

这不会编译,因为getFormattedPrice()在基类上不可用。由于WITH_TAXES实例是 的匿名子类EnumPriceType,因此您无法将局部变量定义为getFormattedPrice()方法可见的类型。

作为元观察,这是强类型语言(如 Java)和“鸭子类型”语言(如 Ruby)之间的关键区别。getFormattedPrice()如果碰巧在那里,Ruby 会很高兴地调用该方法,而不管foo变量中保存的是什么类型的对象。

enum作为另一个元观察,相同的不同常数具有不同的集合方法没有多大意义。如果您不能将所需的一切作为抽象(或具体)方法放在基本枚举类型上,那么您可能使用了错误的工具来解决问题。

于 2011-09-29T15:45:44.023 回答
2

添加

       public String getFormattedPrice(float input) {
        return input + " €";
    }

在覆盖之外作为默认实现。(在声明旁边getPrice。)你可以走了。

您还可以让枚举实现接口,以定义每个人都需要实现的内容。

于 2011-09-29T15:43:29.127 回答
0

那么具有多个实例的 Enum 呢?

没有这样的事情,你的例子也没有证明它。您有一个具有多个值的枚举。他们都是单身人士。

于 2011-09-29T23:43:48.287 回答