Are enum names interned in 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.


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.