Are enum names interned in Java?

JavaEnums

Java Problem Overview


Are enum names interned in Java?

I.e. is it guaranteed that enum1.name() == enum2.name() in case of the same name? And is it safe to compare enum.name() to a String that is guaranteed to be interned.

Java Solutions


Solution 1 - Java

Although there is no explicit guarantee of this, the end result is bound to be such that the comparison always succeeds for enum constants with identical names:

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

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:

protected Enum(String name, int ordinal);

The name is embedded into the generated code in the form of a string literal. According to String documentation,

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

This amounts to an implicit guarantee of your expression succeeding when names of enum constants are identical. However, I would not rely on this behavior, and use equals(...) instead, because anyone reading my code would be scratching his head, thinking that I made a mistake.

Solution 2 - Java

No.

Dasblinkenlight's answer is the best answer we have so far. There he says:

> 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

and there they get interned, because they're string constants.

But, in the JLS, 8.9.2, Enum Body Declarations, there's this:

> 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.

(emphasis mine)

So we'll call the constructor, but we aren't forced to do it in any particular way, and we can manage our own constructor in the compiler.

Therefore, it's completely possible for me to write a correct and JLS-compliant Java compiler that would not intern the names somehow, probably by not having the names stored as a literals. Yes, it would do it on purpose to maliciously break your code, but it would be correct behaviour per spec.


Practically said, Yes.

Every sane implementation will intern the strings. I'd say it's safe to assume this kind of behaviour. It's not guaranteed, though, and therefore if I saw this in real code, I'd be very unsatisfied with it even if it was thoroughly described in a comment.

Please, don't rely on such unspecified and implementation-specific behaviour. If you really, really have to, write a unit test for it. And put an assert in the code, and lots of explaining. Measure whether your approach will actually do anything.

Consider looping over the enum members' names and intern() them manually before using them. That way, it will be immediatelly clear what you're doing. This doesn't work reliably. See comments.

Solution 3 - Java

With strings you're going to want to use the equals method of Strings. That aside, you already have the enum that you could compare with the equality operator. Under what scenario would this arise?

That being said, yes, the .equals method will return true if they are the same.

I'm not sure about equality operator, and without looking it up, I can tell you that it's poor programming to use it if it is.

Solution 4 - Java

The Oracle documentation about Enum says (first line):

> 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.

If this is true then, yes, your enum1.name() == enum2.name() is guaranteed to be true if the names are the same.

Also, in the method 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

For example, if you had two enums, Days and MyDays, where SUNDAY is a common value, == between the enum object values, SUNDAY will return true as you are comparing two strings - see the working example in 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());
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOleg MikheevView Question on Stackoverflow
Solution 1 - JavaSergey KalinichenkoView Answer on Stackoverflow
Solution 2 - JavaPetr JanečekView Answer on Stackoverflow
Solution 3 - JavaNathanView Answer on Stackoverflow
Solution 4 - Javaha9u63arView Answer on Stackoverflow