How to cast a value from one enum to another in Java? - 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

Related

Can I have function types in Java's Enum like Swift?

Is it possible to write an equivalent code in Java for the following swift code? In fact, I want to know if it's possible to have a case of functions inside Java's enum (X, Y in MyEnum)
enum MyEnum{
case X((Int) -> String)
case Y((Double) -> Int)
}
No, you can't; at least, not if you want the differing types to be available when you use the enum. All enum values have to have the same type.
When you want "enum" values to have heterogenous types, you could use a class with static final fields:
final class MyHeterogeneousEnum {
private MyHeterogeneousEnum() {} // Not instantiable.
static final Function<Integer, String> X = ...;
static final Function<Double, Integer> Y = ...;
}
which allows you to use the values with their full type information:
String s = MyHeterogeneousEnum.X.apply(123);
Integer i = MyHeterogeneousEnum.Y.apply(999.0);
Of course, you don't have useful methods like name(), or values() to iterate over the constants in this class, nor is it inherently serializable. You can make implement these yourself - but for values() you have to use wildcards in the return type, in order that all values can be returned:
static Iterable<Function<?, ?>> values() {
return Collections.unmodifiableList(Arrays.asList(X, Y));
}
However, note that a Function with a wildcard input type parameter is pretty much useless: you can't actually pass anything into it (other than null); so the values() method has limited utility.
It is possible (technically), but it might not be that useful, as creating a simple class, that consumes a Function instance.
As you might already know, in Java, the enums represent one or more constants of the same type, which could have their own properties - this include java.util.Function instances. However, these Function instances cannot be passed dynamically at Runtime, but should be rather set at compile time, so that the constant is created.
Of course, you could make each enum constant have a different typed Function, by just creating the enum's constructor Generic:
enum MyEnum {
X((String x) -> "Hello"), Y((Double d) -> 1);
Function<?, ?> function;
MyEnum(Function<?, ?> function) {
this.function = function;
}
}
This, however, is not quite useful (although it compiles just fine). The Function in X doesn't use it's String parameter and returns a fixed value. So does the one in Y.
I'd rather introduce two separate instances of the same class:
class Instance<T, U> {
private Function<T, U> function;
public Instance(Function<T, U> function) {
this.function = function;
}
}
This will allow you to dynamically pass a Function instance, instead of setting it at compile-time.
Yes for sure you can, in java enums can be more that just constants... every one of it values can be an anonymous class (take a look to TimeUnit.class for example)
now, you can do somthing like:
interface IFunction {
double getY(double x);
}
enum Function implements IFunction {
LINE {
#Override
public double getY(double x) {
return x;
}
},
SINE {
#Override
public double getY(double x) {
return Math.sin(x);
}
}
}
and then the implementation
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Function.LINE.getY(i));
System.out.println(Function.SINE.getY(i));
}
}

Get enum values from Enum object

If I were to declare an enum like so
public enum Foo {A, B, C}
then I can get the enum values using
Foo[] values = Foo.values();
However if I wanted to pass Foo as a generic type, like so, I can't get the values since it's generic.
class Bar<E extends Enum<E>> {
public Bar(E e) {
E[] values = e.values(); // not possible
}
}
Is it possible to iterate over the enum values any other way?
You'll have to pass the Class object:
public Bar(Class<E> clazz) {
E[] values = clazz.getEnumConstants();
}
...or, if you have one element e of the enum, you might be able to use e.getDeclaringClass().getEnumConstants(). (Don't use e.getClass().getEnumConstants(), which won't work if your enum constants define their own constant-specific methods.)
Another option: EnumSet.allOf(clazz), which is actually more efficient than clazz.getEnumConstants() in many ways, since it's O(1) and not O(n) in the number of enum constants.

Is there a way to get the enum type from and ordinal value?

What i mean by that is suppose
Enum xyzType {
A,
B,
C,
D
}
I know I can get the ordinal a value of C, by doing xyzType.C.ordinal() which is 2.
Suppose I just have 2, I would to get the enum type C. I can't seem to find anything in the enum API that would do this. I would prefer not to have a huge switch statement to compare each ordinal value and return the enum. Is there a better to do this ?
The simplest approach is:
xyzType xyz = xyzType.values()[ordinalValue];
However, this will create a new array each time. An alternative would be to cache it within the enum:
public enum Xyz {
Foo, Bar;
private static final Xyz[] VALUES = values();
public Xyz fromOrdinal(int ordinal) {
return VALUES[ordinal];
}
}

Enumeration inheritance in Java?

I am doing astrophysical research. I wrote a package containing the classes Star, Band, and Datfile. I also have the enumerated type of BandName. Each star contains several Bands, each Band contains several Datfiles.
I have observational data for several galaxies. For each of these, I make a StarDatabase class (a HashMap of Stars) and a Main class.
The problem I'm having is with the enumerated type of BandName. So far, all of the data I have used has been in the I and V bands. Now I have data in J, H, and K bands. If I simply add J, H, and K to BandName, all of my loops that iterate over all of the items in BandName and do something are now broken.
Any ideas?
Edit: To sum up my problem, I want every package to have its own BandName enum that it can iterate through. But this doesn't work, because the methods in the Star package are expecting objects of type Star.BandName and I am providing objects of type IndividualPackage.BandName.
You can't inherit an enum from another enum, although you can have your enum implement an interface. The technical problem (that all enums implicitly extend java.lang.Enum, thus they can't extend another class, only implement additional interfaces) is no accident:
For the most part, extensibility of enums turns out to
be a bad idea. It is confusing that elements of an extension type are instances of
the base type and not vice versa. There is no good way to enumerate over all of the
elements of a base type and its extension. Finally, extensibility would complicate
many aspects of the design and implementation.
From Effective Java 2nd Edition, Item 34.
However, I don't fully understand your problem: haven't you used values() for iterating through your enum? Then you shouldn't worry about extending your enum with new values.
Please specify more clearly what "broken" is supposed to mean.
Update: so you need to have distinct sets of bands for different types of stars - this can be implemented using distinct enums extending a common interface, e.g.:
interface Band {
String getName();
void doStuff();
...
}
enum BandsVI implements Band {
V, I;
public String getName() { return toString(); }
public void doStuff() { /* do stuff as appropriate for these bands */ }
...
}
enum BandsJHK implements Band {
J, H, K;
public String getName() { return toString(); }
public void doStuff() { /* do stuff as appropriate for these bands */ }
...
}
And you can use these by making your Star class generic:
class Star<T extends Enum<T> & Band> {
private Class<T> bandType;
public Star(Class<T> bandType) { this.bandType = bandType; }
public void printBandNames() {
for (Band b : bandType.getEnumConstants())
System.out.println(b.getName());
}
public void doStuffOnAllBands() {
for (Band b : bandType.getEnumConstants())
b.doStuff();
}
}
...
Star<BandsVI> star1 = new Star<BandsVI>(BandsVI.class);
Star<BandsJHK> star2 = new Star<BandsJHK>(BandsJHK.class);
star1.printBandNames(); // prints V I
star2.printBandNames(); // prints J H K
This works nicely if the bands are organized into distinct groups. If there are stars with mixed band groups, however, you might prefer an alternative approach:
class Star {
private List<? extends Band> bandTypes;
public Star(List<? extends Band> bandTypes) { this.bandTypes = bandTypes; }
public void printBandNames() {
for (Band b : bandTypes)
System.out.println(b.getName());
}
...
}
...
Star star1 = new Star(Arrays.asList(BandsVI.values()));
Star star3 = new Star(Arrays.asList(new Band[]{BandsVI.V, BandsVI.I, BandsJHK.K}));
...
This allows you to set up stars with an arbitrary mix of bands. However, this way you can't use EnumSet or EnumMap on the bands.
All enums implicitly extend java.lang.Enum. Since Java does not support multiple inheritance an enum cannot extend anything else. - http://download.oracle.com/javase/tutorial/java/javaOO/enum.html
This is what I'd do (pseudo-code):
class Band
{
String name;
};
static Band J("J");
static Band K("K");
static ArrayList<Band> JK;
static ArrayList<Band> IHL;
class Star
{
Star(ArrayList<Band> bands)
}
This way you can add bands by just creating more Band objects. Each start has the list of bands it uses so it can iterate over all them.

Difference of Enum between java and C++?

I am learning Enums in java I like to know what are the major differences of Enum in java and C++.
Thanks
In c++ an enum is just a list of integer values.
In java an enum is a class which extends Enum and is more a nice way to write:
class MyEnum extends Enum<MyEnum>
{
public final static MyEnum VE01 = new MyEnum();
public final static MyEnum VE02 = new MyEnum();
}
as enum:
enum MyEnum
{
VE01,VE02;
}
For the Methods of enum see this.
Since a java enum is an object it supports everything a normal java object does.
as giving them values or functions:
enum Binary{
ZERO(0),ONE(1);
Binary(int i)
{
value = i;
}
public final int value;
}
a nice one is anonymous classes:
enum State{
StateA{
public State doSomething()
{
//state code here
return StateB;
}
},
StateB{
public State doSomething()
{
return StateA;
}
};
public abstract State doSomething();
}
In C++, an enumeration is just a set of named, integral constants. In Java, an enumeration is more like a named instance of a class. You have the ability to customize the members available on the enumeration.
Also, C++ will implicitly convert enum values to their integral equivalent, whereas the conversion must be explicit in Java.
More information available on Wikipedia.
Enums in C/C++ are plain Integers.
Enums in Java are objects - they can have methods (with different behavior from one enum instance to the other). Moreoever, the enum class supplies methods which allows iteration over all enum instances and lookup of an enum instance.
C++:
typedef enum { Red, Yellow, Green } Colors;
void canCrossIntersection(Colors c) {
return c == Green;
}
Java:
public enum Colors {
RED(false),
Yellow(false),
Green(true)
;
Color(boolean b) { this.b = b; }
private boolean b;
public boolean canCrossIntersection() { return b; }
}
In Java you can even emulated extensible enums by letting them implement the same interface and then add all of their values to some sort of collection by calling their values() method.
For a semi-answer... C++0x Strongly Typed Enums bring many of the benefits of Java Enums to C++: strong typing, scope and so forth. If your compiler supports C++0x Strongly Typed Enums, you should consider using them.
Reference:
http://www2.research.att.com/~bs/C++0xFAQ.html#enum
A great feature of Java Enums which lacks in C++ is the name() method. This way you can get the Enum value name (as written in the enum definition) without any extra line of code in definition. For example:
enum Type {T1, T2, T3}
Type t = Type.T1;
System.out.println(t.name()); // prints T1

Categories