How Is Values() Implemented for Java 6 Enums

How is values() implemented for Java 6 enums?

Basically, the compiler (javac) translates your enum into a static array containing all of your values at compile time. When you call values(), it gives you a .clone'd() copy of this array.

Given this simple enum:

public enum Stuff {
COW, POTATO, MOUSE;
}

You can actually look at the code that Java generates:

public enum Stuff extends Enum<Stuff> {
/*public static final*/ COW /* = new Stuff("COW", 0) */,
/*public static final*/ POTATO /* = new Stuff("POTATO", 1) */,
/*public static final*/ MOUSE /* = new Stuff("MOUSE", 2) */;
/*synthetic*/ private static final Stuff[] $VALUES = new Stuff[]{Stuff.COW, Stuff.POTATO, Stuff.MOUSE};

public static Stuff[] values() {
return (Stuff[])$VALUES.clone();
}

public static Stuff valueOf(String name) {
return (Stuff)Enum.valueOf(Stuff.class, name);
}

private Stuff(/*synthetic*/ String $enum$name, /*synthetic*/ int $enum$ordinal) {
super($enum$name, $enum$ordinal);
}
}

You can look at how javac 'translates' your classes by making a temporary directory and running:

javac -d <output directory> -XD-printflat filename.java

How are enums implemented in Java?

i believe each instance of the enum is an anonymous final subclass of the enum.

decompile:

public enum Color {
r(0xff0000), g(0x00ff00), b(0x0000ff);
Color(int rgb) {
this.rgb=rgb;
}
final int rgb;
}

and you can see the instances being made:

D:\home\ray\dev\indigoapps\so8032067enumimpl\bin>javap -c Color
Compiled from "Color.java"
public final class Color extends java.lang.Enum{
public static final Color r;

public static final Color g;

public static final Color b;

final int rgb;

static {};
Code:
0: new #1; //class Color
3: dup
4: ldc #16; //String r
6: iconst_0
7: ldc #17; //int 16711680
9: invokespecial #18; //Method "<init>":(Ljava/lang/String;II)V
12: putstatic #22; //Field r:LColor;
15: new #1; //class Color
18: dup
19: ldc #24; //String g
21: iconst_1
22: ldc #25; //int 65280
24: invokespecial #18; //Method "<init>":(Ljava/lang/String;II)V
27: putstatic #26; //Field g:LColor;
30: new #1; //class Color
33: dup
34: ldc #28; //String b
36: iconst_2
37: sipush 255
40: invokespecial #18; //Method "<init>":(Ljava/lang/String;II)V
43: putstatic #29; //Field b:LColor;
46: iconst_3
47: anewarray #1; //class Color
50: dup
51: iconst_0
52: getstatic #22; //Field r:LColor;
55: aastore
56: dup
57: iconst_1
58: getstatic #26; //Field g:LColor;
61: aastore
62: dup
63: iconst_2
64: getstatic #29; //Field b:LColor;
67: aastore
68: putstatic #31; //Field ENUM$VALUES:[LColor;
71: return

public static Color[] values();
Code:
0: getstatic #31; //Field ENUM$VALUES:[LColor;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1; //class Color
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #43; //Method java/lang/System.arraycopy:(Ljava/lang/Obj
ect;ILjava/lang/Object;II)V
20: aload_2
21: areturn

public static Color valueOf(java.lang.String);
Code:
0: ldc #1; //class Color
2: aload_0
3: invokestatic #51; //Method java/lang/Enum.valueOf:(Ljava/lang/Class;L
java/lang/String;)Ljava/lang/Enum;
6: checkcast #1; //class Color
9: areturn

}

How are enums internally represented in Java?

Each enum class is compiled as a class being a subclass of java.lang.Enum. Each enum constant becomes a static final constant within that class. Then, an array $VALUES is created with all of the enum constants, in order of declaration.

You can disassemble the code using the command javap -p -c Ordinals (on the compiled .class file) to find out the details.

Compiled from "Ordinals.java"
public final class Ordinals extends java.lang.Enum<Ordinals> {
public static final Ordinals FIRST;

public static final Ordinals SECOND;

public static final Ordinals THIRD;

private java.lang.String notation; // your custom field

private static final Ordinals[] $VALUES; // all enum constants

public static Ordinals[] values(); // every enum class has this static method
Code:
0: getstatic #1 // Field $VALUES:[LOrdinals;
3: invokevirtual #2 // Method "[LOrdinals;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LOrdinals;"
9: areturn

public static Ordinals valueOf(java.lang.String); // every enum class has this static method
Code:
0: ldc_w #4 // class Ordinals
3: aload_0
4: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
7: checkcast #4 // class Ordinals
10: areturn

private Ordinals(java.lang.String);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #6 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: aload_0
7: aload_3
8: putfield #7 // Field notation:Ljava/lang/String;
11: return

public java.lang.String getNotation();
Code:
0: aload_0
1: getfield #7 // Field notation:Ljava/lang/String;
4: areturn

static {}; // fills the $VALUES array and initializes the static fields corresponding to the enum constants
Code:
0: new #4 // class Ordinals
3: dup
4: ldc #8 // String FIRST
6: iconst_0
7: ldc #9 // String st
9: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #11 // Field FIRST:LOrdinals;
15: new #4 // class Ordinals
18: dup
19: ldc #12 // String SECOND
21: iconst_1
22: ldc #13 // String nd
24: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #14 // Field SECOND:LOrdinals;
30: new #4 // class Ordinals
33: dup
34: ldc #15 // String THIRD
36: iconst_2
37: ldc #16 // String rd
39: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
42: putstatic #17 // Field THIRD:LOrdinals;
45: iconst_3
46: anewarray #4 // class Ordinals
49: dup
50: iconst_0
51: getstatic #11 // Field FIRST:LOrdinals;
54: aastore
55: dup
56: iconst_1
57: getstatic #14 // Field SECOND:LOrdinals;
60: aastore
61: dup
62: iconst_2
63: getstatic #17 // Field THIRD:LOrdinals;
66: aastore
67: putstatic #1 // Field $VALUES:[LOrdinals;
70: return
}

That would translate back to Java as

public final class Ordinals extends java.lang.Enum<Ordinals> {
public static final Ordinals FIRST;

public static final Ordinals SECOND;

public static final Ordinals THIRD;

private String notation;

private static final Ordinals[] $VALUES;

public static Ordinals[] values() {
return $VALUES.clone();
}

public static Ordinals valueOf(String name) {
return (Ordinals) Enum.valueOf(Ordinals.class, name);
}

private Ordinals(String name, int ordinal, String notation) {
super(name, ordinal);
this.notation = notation
}

static {
FIRST = new Ordinals("FIRST", 0, "st");
SECOND = new Ordinals("SECOND", 1, "nd");
THIRD = new Ordinals("THIRD", 2, "rd");
Ordinals[] $VALUES = new Ordinals[3];
$VALUES[0] = FIRST;
$VALUES[1] = SECOND;
$VALUES[2] = THIRD;
Ordinals.$VALUES = $VALUES;
}
}

Class version is totally unrelated to that - it depends on the version of the Java compiler that you used (or on the explicit setting on the compiler to force it to compile for an older Java version).

Does the Enum#values() allocate memory on each call?

Yes.

Java doesn't have mechanism which lets us create unmodifiable array. So if values() would return same mutable array, we risk that someone could change its content for everyone.

So until unmodifiable arrays will be introduced to Java, for safety values() must return new/separate array holding all values.

We can test it with == operator:

MyEnumType[] arr1 = MyEnumType.values();
MyEnumType[] arr2 = MyEnumType.values();
System.out.println(arr1 == arr2); //false

If you want to avoid recreating this array you can simply store it and reuse result of values() later. There are few ways to do it, like.

  • you can create private array and allow access to its content only via getter method like

    private static final MyEnumType[] VALUES = values();// to avoid recreating array

    MyEnumType getByOrdinal(int){
    return VALUES[int];
    }
  • you can store result of values() in unmodifiable collection like List to ensure that its content will not be changed (now such list can be public).

    public static final List<MyEnumType> VALUES = Collections.unmodifiableList(Arrays.asList(values()));

Java enums: implementing common methods, avoiding duplication

Your code example is a bit misleading as it returns the constant with the same ordinal rather than the one with the same property value. In order to abstract the search for a constant with a property value, you have to abstract the property, e.g.

interface TypeWithIntProperty {
int getProperty();
}
enum Number implements TypeWithIntProperty {
ONE(1), TWO(2), THREE(3);

private final int value;

Number(int value) {
this.value=value;
}
public int getProperty() {
return value;
}
}
enum DayOfWeek implements TypeWithIntProperty {
Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7);

private final int value;

DayOfWeek(int value) {
this.value=value;
}
public int getProperty() {
return value;
}
}

public class Helper {
public static <E extends Enum<E>&TypeWithIntProperty>
E getEnumItem(Class<E> type, int value) {
for(E constant: type.getEnumConstants())
if(value == constant.getProperty())
return constant;
throw new IllegalArgumentException("no constant with "+value+" in "+type);
}
}

 

DayOfWeek day=Helper.getEnumItem(DayOfWeek.class, 7);
Number no=Helper.getEnumItem(Number.class, 2);

If the properties have different types, you can make the interface generic:

interface TypeWithIntProperty<T> {
T getProperty();
}
enum Number implements TypeWithIntProperty<String> {
ONE, TWO, THREE;

public String getProperty() {
return name().toLowerCase();
}
}
enum DayOfWeek implements TypeWithIntProperty<Integer> {
Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7);

private final int value;

DayOfWeek(int value) {
this.value=value;
}
public Integer getProperty() {
return value;
}
}

public class Helper {
public static <E extends Enum<E>&TypeWithIntProperty<P>,P>
E getEnumItem(Class<E> type, P value) {
for(E constant: type.getEnumConstants())
if(value.equals(constant.getProperty()))
return constant;
throw new IllegalArgumentException("no constant with "+value+" in "+type);
}
}

 

DayOfWeek day=Helper.getEnumItem(DayOfWeek.class, 7);
Number no=Helper.getEnumItem(Number.class, "two");

A cleaner, but more verbose (under Java 6) alternative is to separate the property abstraction from the type having the property:

interface Property<T,V> {
V get(T owner);
}
enum Number {
ONE, TWO, THREE;
static final Property<Number,String> NAME=new Property<Number,String>() {
public String get(Number owner) { return owner.getName(); }
};

public String getName() {
return name().toLowerCase();
}
}
enum DayOfWeek {
Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7);
static final Property<DayOfWeek,Integer> INDEX=new Property<DayOfWeek,Integer>() {
public Integer get(DayOfWeek owner) { return owner.getIndex(); }
};

private final int index;

DayOfWeek(int value) {
this.index=value;
}
public int getIndex() {
return index;
}
}
public class Helper {
public static <E extends Enum<E>,P>
E getEnumItem(Class<E> type, Property<E,P> prop, P value) {
for(E constant: type.getEnumConstants())
if(value.equals(prop.get(constant)))
return constant;
throw new IllegalArgumentException("no constant with "+value+" in "+type);
}
}

 

DayOfWeek day=Helper.getEnumItem(DayOfWeek.class, DayOfWeek.INDEX, 7);
Number no=Helper.getEnumItem(Number.class, Number.NAME, "two");

This would be much simpler in Java 8 where you can implement Property as DayOfWeek::getIndex or Number::getName instead of inner classes, on the other hand, since we don’t benefit from the single-method interface in Java 6, we can turn this into an advantage by using an abstract base class which can provide the functionality, now even with caching:

abstract class Property<T extends Enum<T>,V> {
final Class<T> type;
final Map<V,T> map;
Property(Class<T> type) {
this.type=type;
map=new HashMap<V, T>();
for(T constant: type.getEnumConstants())
{
T old = map.put(get(constant), constant);
if(old!=null)
throw new IllegalStateException("values not unique: "+get(constant));
}
}
abstract V get(T owner);
T getConstant(V value) {
T constant=map.get(value);
if(constant==null)
throw new IllegalArgumentException("no constant "+value+" in "+type);
return constant;
}
}
enum Number {
ONE, TWO, THREE;
static final Property<Number,String> NAME=new Property<Number,String>(Number.class) {
public String get(Number owner) { return owner.getName(); }
};

public String getName() {
return name().toLowerCase();
}
}
enum DayOfWeek {
Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7);
static final Property<DayOfWeek,Integer> INDEX
=new Property<DayOfWeek,Integer>(DayOfWeek.class) {
public Integer get(DayOfWeek owner) { return owner.getIndex(); }
};

private final int index;

DayOfWeek(int value) {
this.index=value;
}
public int getIndex() {
return index;
}
}

 

DayOfWeek day=DayOfWeek.INDEX.getConstant(7);
Number no=Number.NAME.getConstant("two");

What's the best way to implement `next` and `previous` on an enum type?

Try this:

public enum A {
X, Y, Z;

private static final A[] vals = values();

public A next() {
return vals[(this.ordinal() + 1) % vals.length];
}
}

Implementation of previous() is left as an exercise, but recall that in Java, the modulo a % b can return a negative number.

EDIT: As suggested, make a private static copy of the values() array to avoid array copying each time next() or previous() is called.

enum values() - call each time or assign to variable

Each time you call values() you are creating new array filled with enum constants. You can easy test it with == operator

System.out.println(ExampleEnum.values()==ExampleEnum.values());//prints false

So second option would be better because it creates this array once. But to improve it you could simply store result of values() outside of this method and reuse it when need. This way you would simply invoke it once. You can also create collection of someValue elements earlier, store it as unmodifiable collection (like List) and return it.

So your code could look like:

enum ExampleEnum {
A("A's String"), B("B's String"), C("C's String");
ExampleEnum(String someValue) {
this.someValue = someValue;
}

private final String someValue;

private static final ExampleEnum[] vals = values();
private static final List<String> names = Collections.unmodifiableList(
Stream.of(vals).map(en -> en.someValue).collect(Collectors.toList()));

public static List<String> getAllValues() {
return names;
}
}

Does Java support Non-Incrementing Values for Enums?

Gaps are allowed, in fact you can define an actual constructor.

public enum HttpStatusCode {
OK(200), NO_CONTENT(204), NOT_FOUND(404);
private int status;
private HttpStatusCode(int st) { status = st; }
public int getStatus() { return status; }
}

You still get incremental values by the ordinal().

Complexity of enum.values()

The array returned by Colour.values() always contains the same elements, but values() creates a new array every time it's called (so it's O(n) where n is the number of enum values). And you never modify that array. So calling the method every time you need it is a waste of time. And storing an array in every instance of your DataStructure class is a waste of time and memory. I would simply call the method once and cache that array in a constant:

private static final Colour[] COLOURS = colour.values();

public Colour getRandomColour() {
return COLOURS[rand.nextInt(COLOURS.length)];
}

Just make sure this array is never exposed outside of the class.

Also note the usage of Random.nextInt(limit) which does exactly what you want, is probably faster, and expressed the intent more clearly than using a modulo.



Related Topics



Leave a reply



Submit