【问题标题】:Java Enums can have behavior?Java Enums 可以有行为吗?
【发布时间】:2010-10-18 02:09:58
【问题描述】:

在 Java 中,Enum 可以做 Enums 所做的伟大事情,但也可以有方法(行为和逻辑)。与使用枚举的类相比,这有什么优势?也欢迎简单的例子来说明这一点。

【问题讨论】:

    标签: java oop enums


    【解决方案1】:

    看看 java/joda 时间类,枚举在其中做了很多工作。

    这里是 java.time.Month 的一个例子:

    public enum Month implements TemporalAccessor, TemporalAdjuster {
        JANUARY,
        FEBRUARY,
        MARCH,
        APRIL,
        MAY,
        JUNE,
        JULY,
        AUGUST,
        SEPTEMBER,
        OCTOBER,
        NOVEMBER,
        DECEMBER;
    
        private static final Month[] ENUMS = Month.values();
    
        public static Month of(int month) {
            if (month < 1 || month > 12) {
                throw new DateTimeException("Invalid value for MonthOfYear: " + month);
            }
            return ENUMS[month - 1];
        }
    
        // About a dozen of other useful methods go here 
    
    }
    

    【讨论】:

      【解决方案2】:

      基本上,Java 枚举 类(我认为在字节码级别没有区别),另外还有一个好处是拥有一组已知的固定可能实例并能够使用它们在 switch 语句中。

      您可以使用常规类模拟“已知的固定可能实例集”(无数书籍和文章中描述的“类型安全枚举”模式),但要使其正常工作需要做很多工作(对每个此类重复)关于序列化、equals() 和 hashCode() 以及我可能忘记的其他一些事情,确实是正确的。语言级别的枚举让您免于工作。而且,如上所述,switch 语句中只能使用语言级别的枚举。

      【讨论】:

      【解决方案3】:

      因为枚举实例是单例,您可以在switch 语句中使用它们或与== 一起使用来检查相等性。

      【讨论】:

        【解决方案4】:

        Enum 类型也是实现真正单例的好方法。

        Java 中的经典单例模式通常涉及私有构造函数和公共静态工厂方法,但仍然容易通过反射或(反)序列化进行实例化。枚举类型可以防止这种情况发生。

        【讨论】:

        • 尽管您确实“免费”获得了一些奇怪的方法。 (无论如何,单身人士都是邪恶的。)
        • 我看不懂评论。
        • 有趣的地方。枚举如何防范反射和反序列化?我想我在问,究竟是什么阻止了我通过反射实例化枚举?编译器会抛出检查异常吗?
        • 如果你加载一个枚举类并通过反射获取一个实例,它将起作用,你将得到与通常相同的实例。
        【解决方案5】:

        这是一个简单的例子:

        enum RoundingMode {
            UP {
                public double round(double d) {
                    return Math.ceil(d);
                }
            },
            DOWN {
                public double round(double d) {
                    return Math.floor(d);
                }
            };
        
            public abstract double round(double d);
        }
        

        【讨论】:

        • 你将如何在代码中使用它?我只是这样做吗?双 foo = RoundingMode.round(20.3);或者您会将枚举扩展到子枚举?我被抽象方法迷住了。
        • 抽象方法被 UP 和 DOWN 使用的嵌套类覆盖。你会在这样的代码中使用它: double doMath(RoundMode m, double x, double y) { double d; ... d = m.round(d); ...返回d;您可以传入 RoundingMode.UP 或 RoundingMode.DOWN 作为第一个参数。
        【解决方案6】:

        在我们的项目中,我们将 Enums 用于一些事情,但也许最重要的是用于 i18n 目的 - 每条显示的文本都被赋予一个 Enum。 Enum 类有一个返回字符串的方法,该方法检查正在使用的语言环境,并在运行时从翻译集合中选择正确的翻译。

        这具有双重用途 - 您可以从 IDE 中完成代码,并且永远不要忘记翻译字符串。

        用法非常简单,举个例子几乎是多余的,但这里是如何使用translation-enum

        System.out.println(Translations.GREET_PERSON.trans()+" "+user.getName());
        

        或者,如果你想花哨的话,让 Enum 接受参数,通过一些神奇的字符串操作,这些参数将插入到翻译字符串中的标记位置

        System.out.println(Translations.GREET_PERSON.trans(user.getName());
        

        【讨论】:

        • 有趣的用法,但看起来您可以从类中的一系列静态方法中获得相同的行为。我猜我没有看到使用枚举的优势。
        • 枚举在需要时更容易添加。他们也是自我意识的——你可以在 trans() 中获取枚举本身的字符串——因此,你可以使用它作为关键字来匹配你的翻译表
        【解决方案7】:

        我不太确定问题的标题与其余部分的位置相符。是的,Java 枚举有行为。他们也可以有状态,虽然它应该真的,真的是不可变的状态。 (可变枚举值的想法在 IMO 中非常可怕。)

        基本上,Java 中的枚举是一组固定的对象。好处是您知道如果您有该类型的引用,它总是要么是null,要么是众所周知的集合之一。

        就我个人而言,我真的很喜欢 Java 枚举,并希望 C# 也有它们 - 它们比 C# 的枚举(基本上是“命名数字”)更面向对象。在初始化顺序方面有一些“陷阱”,但它们通常都很棒。

        【讨论】:

        • 你不能用 C# 类模拟 Java 枚举吗?
        • @Vilx:当然可以。在 Java 5 之前,您可以编写自己的类来创建类型安全的枚举对象。 (当然,你仍然可以,只是没有什么意义。)
        • Vilx:你可以,但是有点讨厌。基本上,您使用带有私有构造函数的抽象基类型,并使用可以调用私有构造函数的 nested 类型从它派生。
        • 我想在“真的,真的是不可变的状态”中添加一些真的
        • 你能给我一个带有状态的枚举的简单例子吗?只是想把我的大脑包裹起来。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        • 1970-01-01
        • 2016-02-20
        • 2015-04-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多