2

I have the Color enum with:

  1. RED

  2. BLUE

  3. GREEN

I also have these 3 classes:

  1. Red

  2. Blue

  3. Green

My Testclass uses the attribute private Color color and stores one enum value there. How can I return the corresponding class object when calling getValue() or something on private Color color?

Example: If my Testclass has color = Color.RED, it should return a new instance of the class Red when calling getValue() on it.

3 Answers 3

3

You can make the enum a factory.

interface AColour {
};

static class Red implements AColour {

}

static class Green implements AColour {

}

static class Blue implements AColour {

}

enum Colour {

    RED {

                @Override
                AColour makeColour() {
                    return new Red();
                }

            },
    GREEN {

                @Override
                AColour makeColour() {
                    return new Green();
                }

            },
    BLUE {

                @Override
                AColour makeColour() {
                    return new Blue();
                }

            };

    abstract AColour makeColour();
}

class TestClass {

    Colour colour = Colour.RED;

    AColour make() {
        return colour.makeColour();
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

See Class.forName(String).

Returns the Class object associated with the class or interface with the given string name.

Do not forget to put the full package name of the target. Then you should declare the Color enum like this.

public enum Color {
    RED("package.Red"),
    BLUE("package.Blue"),
    GREEN("package.Green");
    private final String value;
    private Color(String value) {
        this.value = value;
    }
    public String getValue() {
        return value;
    }
}

You may need a specific instance, not just a Class instance.

try {
    Class clazz = Class.forName(Color.RED.getValue());
    if (clazz.isInstance(Red.class)) {
        Red red = (Red)clazz.cast(Red.class);
    } else if (clazz.isInstance(Blue.class)) {
        Blue blue = (Blue)clazz.cast(Blue.class);
    } else if (clazz.isInstance(Green.class)) {
        Green green = (Green)clazz.cast(Green.class);
    }
} catch (ClassNotFoundException classNotFound) {
    // A class named "package.Red" cannot be found
}

Comments

1

I originally suggested a static map of Color enums to classes but chrylis pointed out in the comments it's simpler just to make it a field and pass it to the constructor.

public enum Color {
 RED(Red.class),
 BLUE(Blue.class),
 GREEN(Green.class);

 private Class colorClass;
 public Color(Class classColor)  {
    this.colorClass = classColor;
 }

 public ColorClass getValue() {
     return this.colorClass.newInstance();
 }
}

4 Comments

This is way overkill. Much better to make the Class objects a field on the enum type.
@chrylis Can you explain how you would statically initialize that though? The way I do it avoids needing some sort of setup/initialize method that would need to be called at the right point. I don't see a way to do so, and I think this code is much simpler and more straightforward than the other alternatives. I consider instanceof to be a code smell, and needing to add a new class for every color of the rainbow to also be a code smell. My solution requires one line of additional code when you add a new color. But of course it's all personal preference.
The "initialize" method is just called the constructor.
@chrylis Yeah, I thought that's what you were getting at but I forgot you could pass arguments to the constructor when defining the enum. I edited my answer to reflect your suggestion. Also upvoted your comment, I appreciate the code review :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.