7

I have the following interface:

public interface GenericMethods {
  public String getString();
}

With this interface, I implemented this enum:

public enum SpecificEnum implements GenericMethods {
  A("NOT"), B("RELATED"), C("TEXT");

  SpecificEnum(String string) {
    this.string = string;
  }

  private String string;
  
  @Override
  public String getString() {
    return this.string;
  }
}

Now, I want to be able to call a function with the parameter SpecificEnum.class and be able to call the values() function on that parameter, as well as the interface methods on the returned array elements. Something like this:

class Main {
  public static void main(String[] args) {
    for (GenericMethods gm : getEnums(SpecificEnum.class)) {
      System.out.printf(gm.getString());
    }
  }

  public static T[]<T extends GenericMethods> getEnums(Class<T> enum1) {
    enum1.values();
  }
}

However, after searching a lot, I haven't come across a case using generics with enums that implement interfaces at the same time. I also thinkered a lot with the generic types but I can't find the right syntax to be able to call values() on a generic enum class. The main objective is to have multiple related enums be managed all in the same way.

Phaellow
  • 73
  • 1
  • 6

2 Answers2

9

I suspect you may be looking for something like:

public static <T extends Enum<T> & GenericMethods> T[] getEnums(Class<T> enum1) {
    return enum1.getEnumConstants();
}

public static void main(String[] args) {
    for (GenericMethods gm : getEnums(SpecificEnum.class)) {
        System.out.println(gm.getString());
    }
}

Results:
(demo: https://ideone.com/v6on2p)

NOT
RELATED
TEXT

Changes:

  • moved <T extends GenericMethods> before return type since only there generic method can declare its generic type.
  • modified generic type to <T extends Enum<T> & GenericMethods> to force T to also be subtype of some Enum aside from implementing GenericMethods
  • used getEnumConstants() instead of values() as we are using Class, not enum type.
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • Thank you, works precisely as expected. As a follow up question, there wouldn't be any way to store the generic class inside an unrelated enum attribute because of its generic type declaration limitations, correct? – Phaellow Oct 29 '20 at 17:26
  • @Phaellow Sorry but I am not sure what you mean by "store the generic class". For now I suspect you may be looking for a way to create `Class` which would represent for instance `List` (since we can't create it via code like `List.class` as it will not compile). If that is the case then maybe this will interest you: [Google Gson - deserialize list object? (generic type)](https://stackoverflow.com/q/5554217) - specifically `Type listType = new TypeToken>(){}.getType();` – Pshemo Oct 29 '20 at 17:37
  • Sorry if I wasn't clear, I mean to have a certain enum and inside it a field with type `Class`, like `private Class clazz;`, where T is the generic we have been talking about. I'm pretty sure that type parameter definitions aren't allowed for enums, but there could be a way around this that I don't know about. – Phaellow Oct 29 '20 at 17:53
  • @Phaellow Then no, sorry but I also don't know any workaround for this. But just because I don't know solution doesn't mean there is none, so maybe consider asking separate question about it (just include in it explanation of purpose for which you need that mechanism to avoid [XY problem](https://meta.stackexchange.com/q/66377)). – Pshemo Oct 29 '20 at 17:58
2

Call getEnumConstants() on the Class object. As the javadoc says:

Returns the elements of this enum class or null if this Class object does not represent an enum type.

The signature of your method is wrong too. Here is how to write it:

public static <T extends GenericMethods> T[] getEnums(Class<T> enumClass) {
    return enumClass.getEnumConstants();
}

Of course, it might return null, because there is no guarantee that the Class object is an enum class. E.g. with the following class, getEnums(Foo.class) returns null:

public class Foo implements GenericMethods {
    @Override
    public String getString() {
        return "Boo!!";
    }
}

To make sure that the Class is an enum class, change the method to:

public static <T extends Enum<T> & GenericMethods> T[] getEnums(Class<T> enumClass) {
    return enumClass.getEnumConstants();
}

Tests

getEnums(Foo.class); // fails to compile
SpecificEnum[] enums = getEnums(SpecificEnum.class);
System.out.println(Arrays.toString(enums));

Output

[A, B, C]
Andreas
  • 154,647
  • 11
  • 152
  • 247