Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access the .values() and .ordinal() method of arbitrary enum?

Tags:

java

I would like to have a class that emulates the EnumMap, but stores int values instead of some kind of object. Now obviously you could make an EnumMap that maps to Integers, but that's a lot of autoboxing that I'd like to avoid if it's possible to do so.

So I'd like a class like this:

public class EnumIntAttributeMap
{
    enum Attribute
    {
        Height, Weight;
    }

    private final int[] values;

    public EnumIntAttributeMap()
    {
        this.values = new int[Attribute.values().length];
    }

    public int getValue(Attribute a)
    {
        return this.values[a.ordinal()];
    }

    public void setValue(Attribute a, int value)
    {
        this.values[a.ordinal()] = value;
    }
}

Except I'd like to make a version that's generic across all enums. Now, since the .values() and .ordinal() methods are implicitly added by the compiler, it seems like the only way to access them would be with reflection, which would eat up the performance gains I'm trying to gain by avoiding auto-boxing, but maybe there's something I'm missing.

Any thoughts?

EDIT:

I think my initial question was unclear. I would like a class that takes (as a generic parameter) an enum, and then can use the same operations.

So I could use it with any kind of enum without needing to write the class for each kind of enum each time. Such as:

enum Attribute { Height, Weight }

enum AbilityScore {Str, Dex, Con, Int, Wis, Cha}

IdealClass<Attribute> attributeVersion;

IdealClass<AbilityScore> abilityScoreVersion;

and so on.

like image 785
Lokathor Avatar asked Apr 25 '13 07:04

Lokathor


2 Answers

This is a solution:

public class EnumIntMap<E extends Enum<E>> {

    private final int[] values;

    public EnumIntMap(Class<E> cls)
    {
        this.values = new int[cls.getEnumConstants().length];
    }

    public int getValue(E a)
    {
        return this.values[a.ordinal()];
    }

    public void setValue(E a, int value)
    {
        this.values[a.ordinal()] = value;
    }
}

You will have to initialize the map with the class of the enum as well.

enum Attribute { Height, Weight }

enum AbilityScore {Str, Dex, Con, Int, Wis, Cha}

EnumIntMap<Attribute> attributeVersion = new EnumIntMap(Attribute.class);

EnumIntMap<AbilityScore> abilityScoreVersion = new EnumIntMap(AbilityScore.class);
like image 86
maba Avatar answered Sep 23 '22 00:09

maba


The key to doing this genetically is knowing the generic bound for an enum:

<T extends Enum<T>>

Your class can work for any enum as follows:

public class EnumIntAttributeMap<T extends Enum<T>> {
    private final int[] values;
    private final Class<T> clazz;

    public EnumIntAttributeMap(Class<T> clazz) {
        this.clazz = clazz;
        this.values = new int[clazz.getEnumConstants().length];
    }

    public int getValue(T a) {
        return this.values[a.ordinal()];
    }

    public void setValue(T a, int value) {
        this.values[a.ordinal()] = value;
    }
}

Note that the constructor requires a type token, which is required due to java's runtime type erasure.

like image 41
Bohemian Avatar answered Sep 26 '22 00:09

Bohemian