0

I'm working with an interface that accepts a type parameter:

public interface Container<T>

Now I can have a class as such that implements it:

public class EnumContainer implements Container<Enum>

But now suppose I want a Container for enums that implements a interface called Position:

public interface Position {
   String getAbbreviation();
   String getDescription();
}

How can I define PositionEnumContainer? I've tried this but it's a compile time error:

public class PositionEnumContainer implements Container<Enum & Position>

I do not want to make PositionEnumContainer generic such as:

public class PositionEnumContainer <T extends Enum<T> & Position> implements Container<T>
user8297969
  • 415
  • 1
  • 6
  • 18
  • Why did you put a generic in `Enum`? – dpr Jan 21 '20 at 22:12
  • In the last code snippet, I put `Enum` to indicate that T is an Enum of type T. Enum itself is generic. – user8297969 Jan 21 '20 at 22:19
  • 1
    ...`public class PositionEnumContainer implements Container, Position`? Because your class implements the Container interface, and the Position interface? That's how interfaces work: you list every interface your class implements, separated by a comma. – Mike 'Pomax' Kamermans Jan 21 '20 at 22:29
  • @Mike 'Pomax' Kamermans - Thanks for response. I do not want `PositionEnumContainer` to implement `Position`. Rather, I want the `Container` to hold objects that are both of type `Enum` and of type `Position`. – user8297969 Jan 21 '20 at 22:37
  • Then my counter-question is: why? Those are not unifiable, so just "wanting" that is not good enough: it needs to make sense. By all means, create a `class PositionedEnum implements Enum, Position` and then make something that implements `Container`. Generics is about identifying _the one thing_ that you promise is going to get used, not "one of several completely incompatible things". – Mike 'Pomax' Kamermans Jan 22 '20 at 07:56

1 Answers1

0

You can make PositionEnumContainer implement Container<Enum<? extends Position>>.

If a class extends Enum<? extends Position> then it's an enum class that also implements Position, therefore, PositionEnumContainer will only accept objects that are both of type Enum and of type Position. But unfortunately, Java doesn't know about it, so PositionEnumContainer's producing methods will return Enum<? extends Position>, that can't be implicitly cast back to Position, and you will have to cast it yourself or use safe Enums#narrow method.

public class Enums {
    @SuppressWarnings("unchecked") // only class E can extend Enum<E>
    public static <E extends Enum<E>> E narrow(Enum<E> obj) {
        return (E) obj;
    }
}

Alternatively, you can create the PositionEnum interface that extends Position and can only be implemented by enums and then make PositionEnumContainer implement Container<PositionEnum>. In this case, each ConcretePositionEnum will have to implement PositionEnum<ConcretePositionEnum> instead of Position.

// should only be implemented by enums
// you can verify it with annotation processor
public interface IEnum<E extends Enum<E>> extends Comparable<E> {
    String name();
    int ordinal();
    Class<E> getDeclaringClass();

    @SuppressWarnings("unchecked")
    default E self() { return (E) this; }
}

public interface PositionEnum<E extends Enum<E> & Position> extends IEnum<E>, Position {}
IlyaMuravjov
  • 2,352
  • 1
  • 9
  • 27