Java 中是否存在枚举名称?

Are enum names interned in Java?

枚举名称是否在 Java 中驻留?

即是否保证 enum1.name() == enum2.name() 在同名的情况下?将 enum.name() 与保证被实习的字符串进行比较是否安全。

关于 Enum 的 Oracle 文档说(第一行):

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.

如果这是真的,那么,是的,如果名称相同,您的 enum1.name() == enum2.name() 保证是真的。

此外,在方法 name() javadoc:

public final String name() Returns the name of this enum constant, exactly as declared in its enum declaration. Most programmers should use the toString() method in preference to this one, as the toString method may return a more user-friendly name. This method is designed primarily for use in specialized situations where correctness depends on getting the exact name, which will not vary from release to release. Returns: the name of this enum constant

例如,如果您有两个枚举,DaysMyDays,其中 SUNDAY 是一个公共值,== 在枚举对象值之间,SUNDAY 将 return 为真您正在比较两个字符串 - 请参阅 http://ideone.com/U1Bmcw.

中的工作示例
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static enum Day{SUNDAY, MONDAY, TUESDAY};
    public static enum MyDays{SUNDAY};

    public static void main (String[] args) throws java.lang.Exception
    {
        MyDays m = Ideone.MyDays.SUNDAY;
        Day d = Ideone.Day.SUNDAY;

        System.out.println(d.name() == m.name());
    }
}

对于字符串,您需要使用字符串的 equals 方法。除此之外,您已经有了可以与相等运算符进行比较的枚举。什么情况下会出现这种情况?

也就是说,是的,如果它们相同,.equals 方法将 return 为真。

我不确定相等运算符,不用查找,我可以告诉你,如果是,使用它是糟糕的编程。

虽然对此没有明确的保证,但最终结果必然是 enum 个具有相同名称的常量的比较总是成功:

enum A {enum1};
enum B {enum1};
System.out.println(A.enum1.name() == B.enum1.name()); // Prints "true"

原因是 Java 编译器构造 Enum 的子类的方式是它们最终调用 Enum 唯一受保护的构造函数,将其传递给名称enum 值:

protected Enum(String name, int ordinal);

名称以字符串文字的形式嵌入到生成的代码中。根据 String 文档,

All literal strings and string-valued constant expressions are interned.

enum 常量的名称相同时,这相当于对表达式成功的隐式保证。但是,我不会依赖这种行为,而是使用 equals(...),因为任何阅读我的代码的人都会挠头,认为我犯了错误。

没有

是我们迄今为止的最佳答案。他在那里说:

The reason for this is that Java compiler constructs subclasses of Enum in such a way that they end up calling Enum's sole protected constructor, passing it the name of enum value

他们在那里被实习,因为他们是字符串常量。

但是,在 the JLS, 8.9.2, Enum Body Declarations 中,有这个:

In practice, a compiler is likely to mirror the Enum type by declaring String and int parameters in the default constructor of an enum type. However, these parameters are not specified as "implicitly declared" because different compilers do not need to agree on the form of the default constructor. Only the compiler of an enum type knows how to instantiate the enum constants; other compilers can simply rely on the implicitly declared public static fields of the enum type (§8.9.3) without regard for how those fields were initialized.

(强调我的)

所以我们将调用构造函数,但我们不强制以任何特定方式执行此操作,我们可以在编译器中管理我们自己的构造函数。

因此,我完全有可能编写一个正确且符合 JLS 的 Java 编译器,它不会以某种方式保留名称,可能是因为没有将名称存储为文字。是的,它会故意这样做以恶意破坏您的代码,但根据规范这是正确的行为。


实际说,是的

每个理智的实现都会实习字符串。我会说 假设 这种行为是安全的。但是,这并不能保证,因此如果我在真实代码中看到它,即使在评论中对其进行了详尽的描述,我也会对它非常不满意。

请不要依赖这种未指定和特定于实现的行为。如果你真的,真的必须,为它写一个单元测试。并在代码中添加一个 assert,并进行大量解释。衡量你的方法是否真的有用。

考虑在使用 enum 成员的名字和 intern() 之前手动循环它们。这样,您将立即清楚您在做什么。 这不能可靠地工作。查看评论。