1

I have multiple enum classes . For example

   public class enum Animal { 
        DOG,
        LION;
} 
    public class enum Bird { 

     OSTRICH,
     CROW };
}

I want to have a Map<String, Enums > where i can store these enum classes as values and then fetch them based on keys . For example Map<String, Enumclass> such that it gives me the Enum when i pass the key to the Map. For example map.get("Animal") should return me the enum Animal and then i can do operations like Animals.valueOf();

I was able to store the enums in a private Map<String, Class<? extends Enum>> Map; but not able to retreive and cast it back to the proper enum classes. Is it possible to do this

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Aman Kumar Sinha
  • 407
  • 6
  • 17
  • 1
    Is this **really** the code you have for your enums or did you just guess and wrote something from your memory? Because this is not any java syntax I am familiar with. – OH GOD SPIDERS May 31 '23 at 15:54
  • How are you using these "enums" in your code? Could you provide a minimal example? – Mr. Polywhirl May 31 '23 at 15:55
  • @aled No it does not . I want to retrieve the entire enum class not just the enum within it – Aman Kumar Sinha May 31 '23 at 16:00
  • Here is my method from the duplicate https://stackoverflow.com/a/43664038/2323964 If you want to use something other than the literal enum name, just implement a common interface like @Mr.Polywhirl suggest and use whatever property from that – Novaterata May 31 '23 at 16:11
  • _"For example map.get("Animal") should return me the enum Animal"_ - that's impossible: methods cannot return classes, they can only return _instances_ of classes, i.e. objects. The enum entries DOG, LION etc. are in fact objects - they're instances of the enum class Animal. So a method such as `map.get` can only return DOG etc but not Animal. When you had it return a `Class extends Enum>` that was actually returning an instance of the `Class` class. – k314159 May 31 '23 at 16:17
  • 3
    You can return `Aminal.class`, and use it with `Enum.valueOf(map.get("Animal"), "DOG")`. – Johannes Kuhn May 31 '23 at 16:40

4 Answers4

3

You will need to have your enums implement a common interface like so:

import java.util.*;

public class Zoo {
    private static final Map<String, ZooAnimal> animals;

    static {
        Map<String, ZooAnimal> tmp = new HashMap<>();
        tmp.put("CHEETAH", Cat.CHEETAH);
        tmp.put("LION", Cat.LION);
        tmp.put("PANTHER", Cat.PANTHER);
        tmp.put("TIGER", Cat.TIGER);
        tmp.put("HAWK", Bird.HAWK);
        tmp.put("OSTRICH", Bird.OSTRICH);
        tmp.put("OWL", Bird.OWL);
        animals = Collections.unmodifiableMap(tmp);
    }

    public static void main(String[] args) {
        ZooAnimal animal = animals.get("PANTHER");
        if (animal != null && animal instanceof Cat) {
            // A panther is a cat
            System.out.printf("A %s is a cat%n", animal.getName().toLowerCase());
        }
    }

    private interface ZooAnimal {
        String getName();
    }

    public enum Cat implements ZooAnimal {
        CHEETAH, LION, PANTHER, TIGER;

        @Override
        public String getName() {
            return this.name();
        }
    };

    public enum Bird implements ZooAnimal {
        HAWK, OSTRICH, OWL;

        @Override
        public String getName() {
            return this.name();
        }
    };
}

If you want the values, you can use the generic Enum class:

import java.util.*;

public class Zoo {
    private static final Map<String, Class<? extends Enum<?>>> animals;

    static {
        Map<String, Class<? extends Enum<?>>> tmp = new HashMap<>();
        tmp.put("BIRD", Bird.class);
        tmp.put("CAT", Cat.class);
        animals = Collections.unmodifiableMap(tmp);
    }

    public static void main(String[] args) {
        Class<? extends Enum<?>> animal = animals.get("CAT");
        // Print the values
        for (Enum<?> c : animal.getEnumConstants()) {
            System.out.println(c.name()); // CHEETAH, LION, PANTHER, TIGER
        }
    }

    public enum Cat {
        CHEETAH, LION, PANTHER, TIGER;
    };

    public enum Bird {
        HAWK, OSTRICH, OWL;
    };
}
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

* Updating my answer since the question is updated with more explanations.

I'm going to provide another approach which is adding another dimension to the Enum to indicate the Animal type, and in this case you don't need to cast to multiple Enums:

public enum AnimalType 
{
    BIRD, CAT;
}
public enum Animal 
{
    CHEETAH(AnimalType.CAT, "Cheetah"),
    LION(AnimalType.CAT, "Lion"),
    HAWK(AnimalType.BIRD, "Hawk"),
    OWL(AnimalType.BIRD, "Owl");
 
    private AnimalType type;
    private String name;
 
    Animal(AnimalType type, String name) {
        this.type = type;
        this.name = name;
    }
 
    public String getName() {
        return name;
    }

    public AnimalType getType() {
        return type;
    }

    public static Optional<Animal> fromName(String name) {
        return Arrays.stream(Animal.values())
            .filter(a -> a.name.equals(name))
            .findFirst();
    }

    public static List<Animal> fromType(AnimalType type) {
        return Arrays.stream(Animal.values())
            .filter(a -> a.type == type))
            .collect(Collectors.toList());
    }
}
Islam Elbanna
  • 1,438
  • 2
  • 9
  • 15
0

There doesn't appear to be an exact solution to what you're looking to achieve.

Essentially, I believe that since an enum is considered a static object, you cannot cast the static reference into a new object.

You would have to use a Class<Animal> type.
And, at that rate, you're better off just utilizing the Enum class.

Here is a tutorial on Java reflection with enums, for this specific requirement.
Examining Enums (The Java™ Tutorials > The Reflection API > Arrays and Enumerated Types).

Since you know that your map values are going to be enum objects, you can utilize the Enum#valueOf method, to obtain a single value.

If you want a list of values, similar to the values method, you can use an array of Enum and utilize the Class#getEnumConstants.

Map<String, Class<? extends Enum>> map = new HashMap<>();
map.put("Animal", Animal.class);
map.put("Bird", Bird.class);
for (Enum value : map.get("Animal").getEnumConstants()) 
    System.out.println(value.name());
Reilas
  • 3,297
  • 2
  • 4
  • 17
-1

I found a solution through Reflections . It can be sone like this

Map<String, Class<? extends Enum<?>>> errorCodes = errorCodeMap.getErrorCodeMap();
            Class<? extends Enum<?>> enumClass = errorCodes.get(code.substring(0, 1));
            Enum<?>[] enumConstants = enumClass.getEnumConstants();
            Class<?> actualEnumClass = enumConstants[0].getDeclaringClass();
            StringBuilder errorCode = new StringBuilder().append(prefix).append(code);
            Enum<?> errorEnum = Enum.valueOf(actualEnumClass.asSubclass(Enum.class), errorCode.toString());
Aman Kumar Sinha
  • 407
  • 6
  • 17