1

I have that enum:

enum MyNameIsDynamic {
  LOW,
  MEDIUM,
  HIGH
}

And now the question is:
It is possible to create dynamically instance of that based only on its name? I mean something like that:

Instead of this:

MyNameIsDynamic myEnum;
String valueOfEnum = myEnum.LOW.toString();

I want something like that:

String nameOfMyEnum = "MyNameIsDynamic";
Enum(nameOfMyEnum) myEnum; //Name of enum based on string
String valueOfEnum = myEnum.LOW.toString();

Well i don't know how to exactly show what i want, but i hope that "strange" example above will be enough.
I know it is possible with object based on Class's name, but is it too with Enums?
Please help me guys if that question is not abstract ^_^

Brarord
  • 611
  • 5
  • 18
  • When you know the name of the enum, what do you need this workaround for? – akuzminykh May 11 '20 at 05:36
  • How would you use this? Are you suggesting you have multiple Enum's with a .LOW value? – matt May 11 '20 at 05:37
  • Related: https://stackoverflow.com/questions/9886266/is-there-a-way-to-instantiate-a-class-by-name-in-java – Lino May 11 '20 at 05:37
  • I have many enums and I need to extract their content based on the name. I am writing an application to convert types. If I choose a type from the list, I need to dynamically generate a list of types to which the selected type can be converted. This information is contained in enums. For example, I have "JavaEnum" and there is information that java can be converted to TypeScript and Python. – Brarord May 11 '20 at 05:43
  • string (name) to enum is `valueOf`. enum to string (name) is `toString`. also look for "java get enum by name". – Zabuzard May 11 '20 at 05:47
  • 1
    What you want is not possible. You could go for dynamic programing and work with class tokens over reflection but it really sounds like your architecture/approach is just not good and should be improved instead. I would suggest you share a concrete snippet of your real code and then people could come up with better designs. – Zabuzard May 11 '20 at 06:05

3 Answers3

3

Enum objects automatically instantiated

You said:

create dynamically instance

Instances of an enum are made only once: when the class is loaded. Each constant name on that element is automatically assigned an instance of the enum`s class. Without resorting to some reflection/introspection sorcery, you cannot otherwise instantiate enum objects.

Enum::toString

The toString method generates a String object holding the text of the constant name.

Enum.valueOf

To go the other direction, starting with a constant name, and wanting to get an enum object, call valueOf.

Example

enum FanSpeed {
  LOW,
  MEDIUM,
  HIGH
}

Access one of the already-instantiate objects:

FanSpeed initialSpeed = FanSpeed.LOW ;

Or achieve the same effect by name:

FanSpeed initialSpeed = 
        Enum.valueOf( 
            FanSpeed.class , 
            "LOW" 
        )
;

Or use the shorter version via the enum class itself: FanSpeed.valueOf( "LOW" ).

This string-based approach is generally not necessary. By definition, all of the enum’s objects are known at compile-time. So you should be passing around the enum objects, not their names.

Be aware that the two approaches shown above both access an object that has already been instantiated when your enum class loaded. Neither approach does any instantiation, except indirectly by causing the enum’s class to load.

Class name by Reflection

If your goal is to get the class of the enum by name, use reflection.

The class named Class represents a particular class. To obtain a Class object for a particular class, call Class.forName while passing the name of the desired class as a string.

Class.forName( "com.basil.FanSpeed" )

Verify that the class is indeed an enum by calling Class::isEnum.

From that Class object, you can get an array of all the enum’s objects by calling getEnumObjects.

Obtain a specific enum object via this Class object by passing the constant name to Enum.valueOf as seen above.

Enum.valueOf( 
    Class.forName( "com.basil.FanSpeed" ) ,
    "LOW"
)

Caveat: Use reflection only as a last resort. Often, use of reflection is a “code smell”, indicative of a design strategy needing revision.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Well thanks for answer but we have a little misunderstanding there. The problem is "FanSpeed" is unknown. I can't declare enum like that. I need to get enum Class (FanSpeed) using parameter. Something like that: `"FanSpeed" initialSpeed;` – Brarord May 11 '20 at 05:59
  • 1
    @Brarord See my section added to the end. – Basil Bourque May 11 '20 at 06:17
  • While it's not what the OP asks for, it should be noted that `Enum.valueOf(MyEnum.class, "LOW")` can be simplified to `MyEnum.valueOf("LOW")` using a method that is synthesized by the compiler. – Stephan Herrmann May 12 '20 at 16:44
  • @StephanHerrmann That syntax does not track with the direction of the Answer leading to `Class.forName`. But I added a mention, for the sake of completeness. Thank you. – Basil Bourque May 12 '20 at 21:51
3

Just like with objects, you cannot create a left hand name. So you can get your enum constant though.

public class Enunck{
    enum Junk{
        A,B;
    }
    public static void main(String[] args) throws Exception{
        Class<?> X = Class.forName("Enunck$Junk");
        for(Object o: X.getEnumConstants()){
            System.out.println(o);
        }
        Enum<?> e = (Enum<?>)X.getEnumConstants()[0];
    }
}

That will show all of the enum constants, and even cast one of the constants to an Enum. You won't be able to get it to say. `"Junk" e = ...;

matt
  • 10,892
  • 3
  • 22
  • 34
2

Java makes sure that the instance of enum will be created only once, in fact you could create singletons with enums.

Anyway I couldn't totally understand your requirements so I would like to share 2 code snippets that might be helpful:

Snippet 1 - totally dynamic approach:

Here you know only string name of enum class (MyNameIsDynamic) I've placed it in a default package but in general the first like would require full package name like com.example.MyNameIsDynamic

Class cl = Class.forName("MyNameIsDynamic");
Enum low1 = Enum.valueOf(cl, "LOW");
System.out.println(low1 + " " + low1.getClass().getName());

Snippet 2

MyNameIsDynamic low2 = MyNameIsDynamic.valueOf("LOW");
System.out.println(low2 + " " + low2.getClass().getName());

In this approach you know what the class and the string value (LOW)

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97