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 callingEnum's
sole protected constructor, passing it the name ofenum
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 declaringString
andint
parameters in the default constructor of anenum
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 anenum
type knows how to instantiate theenum
constants; other compilers can simply rely on the implicitly declaredpublic static
fields of theenum
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 This doesn't work reliably. See comments.enum
members' names and intern()
them manually before using them. That way, it will be immediatelly clear what you're doing.