Keating
Keating

Reputation: 3530

Can I specify ordinal for enum in Java?

The ordinal() method returns the ordinal of an enum instance.
How can I set the ordinal for an enum?

Upvotes: 83

Views: 113550

Answers (8)

Sam Ginrich
Sam Ginrich

Reputation: 851

The accepted answer got nearly everything wrong.

It is important be aware of the risk when working with relection operations, still in many cases it is required to correct Java design features; one security case implies the need to cleanup sensitive on shutdown, which e.g. for String-s is already awkward.

The question considered the ordinal field only, for consistency the name field needs to be synchronized. Following function is an extension of Enginer's answer, verified with Java 8.

    public static void setEnumInPlace(final Enum<?> e, final int newOrdinal)
    {
        try
        {
            final Class<?> ecl = e.getClass();

            final Field ordField = Enum.class.getDeclaredField("ordinal");
            final Field nameMember = Enum.class.getDeclaredField("name");

            ordField.setAccessible(true);
            nameMember.setAccessible(true);

            // access final ordinal
            final Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(ordField, ordField.getModifiers() & ~Modifier.FINAL);

            ordField.setInt(e, newOrdinal);

            // sync name
            final String strNewName = (String) nameMember.get(ecl.getEnumConstants()[newOrdinal]);
            nameMember.set(e, strNewName);
        }
        catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e1)
        {
            System.err.println("FAILED, " + e1.getMessage());
        }
    }

Upvotes: 0

blubb
blubb

Reputation: 9910

As the accepted answer points out, you can't set the ordinal. The closest you can get to this is with a custom property:

public enum MonthEnum {

    JANUARY(1),
    FEBRUARY(2),
    MARCH(3),
    APRIL(4),
    MAY(5),
    JUNE(6),
    JULY(7),
    AUGUST(8),
    SEPTEMBER(9),
    OCTOBER(10),
    NOVEMBER(11),
    DECEMBER(12);

    MonthEnum(int monthOfYear) {
        this.monthOfYear = monthOfYear;
    }

    private int monthOfYear;

    public int asMonthOfYear() {
        return monthOfYear;
    }

}

Note: By default, enum values start at 0 (not 1) if you don't specify values. Also, the values do not have to increment by 1 for each item.

Upvotes: 10

Enginer
Enginer

Reputation: 3128

You can update ordinal using reflection:

private void setEnumOrdinal(Enum object, int ordinal) {
    Field field;
    try {
        field = object.getClass().getSuperclass().getDeclaredField("ordinal");
        field.setAccessible(true);
        field.set(object, ordinal);
    } catch (Exception ex) {
        throw new RuntimeException("Can't update enum ordinal: " + ex);
    }
}

Upvotes: 6

Bozho
Bozho

Reputation: 597382

You can't set it. It is always the ordinal of the constant definition. See the documentation for Enum.ordinal():

Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

And actually - you should not need to. If you want some integer property, define one.

Upvotes: 72

Matt
Matt

Reputation: 2189

You can control the ordinal by changing the order of the enum, but you cannot set it explicitly like in C++. One workaround is to provide an extra method in your enum for the number you want:

enum Foo {
  BAR(3),
  BAZ(5);
  private final int val;
  private Foo(int v) { val = v; }
  public int getVal() { return val; }
}

In this situation BAR.ordinal() == 0, but BAR.getVal() == 3.

Upvotes: 91

donnyton
donnyton

Reputation: 6054

The easy answer: just change the order of the constants. The first defined will be 0, the second will be 1, etc. However, this may not be practical if you have constantly changing code, or enums will many many values. You can define a custom method to work around the default ordinal, but MAKE SURE it is well documented to avoid confusion!

public enum Values
{
    ONE, TWO, THREE, FOUR;

    public int getCustomOrdinal()
    {
        if(this == ONE)
        {
            return 3;
        }
        else if(this == TWO)
        {
            return 0;
        }
        ...
    }
}

Upvotes: -6

Piyush Mattoo
Piyush Mattoo

Reputation: 16153

Check out the Java Enum examples and docs

Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

Upvotes: 0

SJuan76
SJuan76

Reputation: 24895

From http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Enum.html

public final int ordinal()Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

Returns: the ordinal of this enumeration constant

If you have

public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }

then SUNDAY has an ordinal of 0, MONDAY is 1, and so on...

Upvotes: 2

Related Questions