Search code examples
javagenericsenumsinterfacebounded-types

Using an Interface as a super type for Enum classes - problem with accessing Enum-specific methods


I've been attempting to implement an interface in my enums in order to have rules for a simulation I'm making.

I am trying to access enum-methods such as values() and ordinal() (on objects).

However, even with upper-bounding my classes with my interface name, I still cannot access these methods without overriding them in my interface, which won't work.

public interface State{
    public static void setTileSize(int size){
        return;
    }

    public void draw(PApplet app, int x, int y);

    public Object updateState(int[] allNeighbours);

    public int getColour();

}

enum WireWorld implements State{ // WireWorld
    WIRE(new Color(100, 100, 100)) {
        public WireWorld updateState(int[] allNeighbours){
            if (allNeighbours[1] >= 1){
                return TIP;
            }
            return WIRE;
        }
    }, ...
public class Tile<T extends State> {
     public Tile() {
        int enumCount = T.values().length;
    }
}

I'm trying to call the constructor on Tile and it doesn't work.


Solution

  • You need to provide an indication that T extends Enum as it was mentioned by @Slaw in the comments.

    We can declare multiple type bound by chaining them using ampersand sign & and since Enum is a class it needs to be mentioned before interface State (see) :

    public class Tile<T extends Enum<T> & State>
    

    Assuming that Tile is meant to hold a reference to an enum member of type T and invoke methods like ordinal() and name() on it. Now compiler will allow doing that, since it knows that T extends Enum<T>.

    And seems like your intention was to define an instance variable enumCount in the Tile class that will hold a number of enum members. In order to initialize it, you need to provide an instance of Class<T> as a parameter to the constructor. And one of the way to get access to all enum constants Class<T> is through EnumSet.allOf().

    public class Tile<T extends Enum<T> & State> {
        private int enumCount;
        private T item;
        
        public Tile(Class<T> enumClass) {
            this.enumCount = EnumSet.allOf(enumClass).size();
        }
        
        public void someMethod() {
            item.ordinal(); // that will compile
            item.name();    // that will compile as well
        }
        
        // ...
    }