Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are enum names interned in Java?

Tags:

java

enums

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.

like image 831
Oleg Mikheev Avatar asked Jan 12 '15 18:01

Oleg Mikheev


People also ask

How is enum stored in Java?

A Java enum is a data type that stores a list of constants. You can create an enum object using the enum keyword. Enum constants appear as a comma-separated list within a pair of curly brackets. An enum, which is short for enumeration, is a data type that has a fixed set of possible values.

Where are enums stored in Java?

In Java, there should only be one instance of each of the values of your enum in memory. A reference to the enum then requires only the storage for that reference. Checking the value of an enum is as efficient as any other reference comparison.

What is enum name in Java?

The name() method of Enum class returns the name of this enum constant same as declared in its enum declaration. The toString() method is mostly used by programmers as it might return a more easy to use name as compared to the name() method.

Should enum names be all caps?

Because they are constants, the names of an enum type's fields are in uppercase letters. You should use enum types any time you need to represent a fixed set of constants.


2 Answers

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.

like image 65
Sergey Kalinichenko Avatar answered Sep 20 '22 19:09

Sergey Kalinichenko


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.

like image 31
Petr Janeček Avatar answered Sep 18 '22 19:09

Petr Janeček