开发者

How to cast a value from one enum to another in Java?

How can I cast a value from Enum1 to Enum 2 in Java? Here is an example of what I'm trying to do :

public enum Enum1 {
  ONE,
  TWO,
  THREE;
}

public enum Enum2 {
  FOUR,
  FIVE,
  SIX;
}

So I want to do something like this:

Enum2 en2 = (Enum2)ONE;

Is it possible and how can I do开发者_开发问答 that?

Thanks in advance!


You cannot cast from one enum to another, however each enum has guaranteed order, and you can easily translate one enum to another (preserving order). For example:

enum E1 {
    ONE, TWO, THREE,
}

enum E2 {
    ALPHA, BETA, GAMMA,
}

we can translate E1.TWO to/from E2.BETA by:

static E2 E1toE2(E1 value) {
    return E2.values()[value.ordinal()];
}

static E1 E2toE1(E2 value) {
    return E1.values()[value.ordinal()];
}


The answer depends on what the "casting" should do...

Casting by ordinal position

In the provided example, there is no commonality between the two sets of enum values so I'm assuming the intention was to translate by ordinal position so Enum1.ONE => Enum2.FOUR, Enum1.TWO => Enum2.FIVE and Enum1.THREE => Enum2.SIX. This can be done as follows:

Enum2 en2 = Enum2.values()[Enum1.ONE.ordinal()];

A natural follow-on question is how this can be extended to a generic function that does the same for any two enum types. Not for the faint hearted but this does the job - it requires the Google Guava library:

public <F extends Enum<F>> F castByOrdinal(Enum<?> e, Class<F> fClass) {
    return Iterators.get(EnumSet.allOf(fClass).iterator(), e.ordinal());
}

If Guava isn't being used, it can be done manually in a few more lines of code:

public <F extends Enum<F>> F castByOrdinal(final Enum<?> e, final Class<F> fClass){
    final Iterator<F> iter = EnumSet.allOf(fClass).iterator();
    int count = 0;
    F fValue = null;
    while (count <= e.ordinal()) {
        if (!iter.hasNext()) {
            return null; // ...Or throw an exception e.g. IndexOutOfBoundsException
        }
        fValue = iter.next();
        count++;
    }

    return fValue;
}

Example usage:

Enum2 en2 = castByOrdinal(Enum1.ONE, Enum2.class);

Casting by shared enum value names

There is another possible way of casting between enums that share some of the same value names.

E.g:

enum Shape {
    TRIANGLE, SQUARE, PENTAGON, HEXAGON, UNKNOWN, NOT_APPLICABLE
}

enum Size {
    SMALL, MEDIUM, LARGE, UNKNOWN, NOT_APPLICABLE
}

The casting will only work for common values (i.e. UNKNOWN and NOT_APPLICABLE above) and can be done as follows:

Size size = Size.valueOf(Shape.UNKNOWN.name());

This will throw an IllegalArgumentException if the value name does not exist in the target enum. The generic method for this casting is a bit simpler:

public <F extends Enum<F>> F castByName(final Enum<?> e, final Class<F> fClass) {
    return F.valueOf(fClass, e.name());
}

Example usage:

Size size = castByName(Shape.UNKNOWN, Size.class);


You can define a method in Enum1 to return the corresponding Enum2:

enum Enum1 {
    ONE {
        @Override
        public Enum2 toEnum2() {
            return Enum2.ALFA;
        }
    },
    TWO {
        @Override
        public Enum2 toEnum2() {
            return Enum2.BETA;
        }
    }
    ,
    THREE {
        @Override
        public Enum2 toEnum2() {
            return Enum2.GAMMA;
        }
    }
    ;

    public abstract Enum2 toEnum2();
}

enum Enum2 {
    ALFA, BETA, GAMMA;
}

or, a bit more readable (IMO):

enum Enum1 {
    ONE(Enum2.ALFA), 
    TWO(Enum2.BETA), 
    THREE(Enum2.GAMMA);

    private final Enum2 enum2;

    private Enum1(Enum2 enum2) {
        this.enum2 = enum2;
    }

    public Enum2 toEnum2() {
        return enum2;
    }
}

enum Enum2 {
    ALFA, BETA, GAMMA;
}

EDIT:
if you need to maintain the 2 enums decoupled, create a map containing the mapping from Enum1 to Enum2 (in a 3rd utility class).


It's not possible. Enum1 and Enum2 are different types with nothing in common.


Even though this ticket was active quite a while ago I'm adding another possibility:

You could also create a Map e.g. like this:

HashMap<Enum1, Enum2> e1ToE2 = new HashMap<Enum1, Enum2>();
e1ToE2.put(Enum1.ONE, Enum2.FOUR);
e1ToE2.put(Enum1.TWO, Enum2.FIVE);

usage

Enum2 e2 = e1ToE2.get(Enum1.ONE);

(+) you dont have to double check the order of your elements

(+) easy to read

(+) fast

(-) requires space

Correct me if I'm wrong :)


You can't do that, because they're objects of different classes.

You could convert from one to the other based on ordinal value or name, but I'd question the design of any program that needed to do that.


You can't ; but you can create a static method in your enums, with a translation code. But you must have a clear idea of the rules you want to implement.


A cast operation is not possible, but you can write a static member function for enum1 that casts enum2 to enum1:

public static Enum1 fromEnum2(Enum2 enum2) {
    ...
}

By the way, you can assign an ID to every constant of both enums which simplifies the implementation.

Here is a tutorial on enums.


It probably won't help you, but you can have

public enum Enum1 implements MyInterface {...}
public enum Enum2 implements MyInterface {...}

We don't have enough information about what you are trying to do to help you. It makes no sense as it is to cast an enum to another enum.


You cannot cast from one enum to another, however each enum has guaranteed order, and you can easily translate one enum to another


If you need a default value:

Arrays.stream(Enum2.values())
      .filter(value -> value.name().equals(Enum1.ONE.name()))
      .findFirst()
      .orElse(Enum2.FOUR)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜