javagenericsinheritanceenumsenumset

EnumSet as a parameter in generic Interface


I've a use case :

inteface A{
  get(EnumSet<?> fetchModes);
}
class B implements A{

  //Here FetchMode is an enum
  get(EnumSet<FetchMode> fetchMode){
   //Some logic here
  }
}

But it's throwing compile time error :

Method get of class B has the same erasure as get(EnumSet fetchMode) of type A but doesn't override it.

I had read that Enums cannot be generic but is there any way to implement this usecase ? (Basically want the EnumSet to be generic and different implementations can pass different Enums)


Solution

  • A method can override another if the argument types match exactly, but yours doesn't. Eventhough EnumSet<FetchMode> is a subtype of EnumSet<?>, they are not exactly the same. You are not overriding the super class method get(EnumSet<?> fetchModes); in your subclass, rather you are overloading it with a different parameter type. Both of these has the same signature due to erasure when you inspect or decompile the bytecode which is get(EnumSet fetchModes) and your compiler starts complaining.

    This is covered in JLS §8.4.8.1:

    A class cannot have two member methods with the same name and type erasure

    A naive attempt at fixing the problem is to change the parameter type such that it is compatible with that of the super class, overriding the method properly in your sub class.

    @Override
    public void get(EnumSet<?> fetchModes) {
    
    }
    

    Though this fixes the compiler error after a fashion, it is still not elegant since it allows your EnumSet to store any Object. But ideally you may want it to store only some subtype of Enum. This idiom supports that.

    What you have to do is declare a generic interface with bounded type parameter and then implement it by overriding the method properly as shown below.

    public interface A<E extends Enum<E>> {
        void get(EnumSet<E> fetchModes);
    }
    
    public class B implements A<FetchMode> {
        @Override
        public void get(EnumSet<FetchMode> fetchModes) {
    
        }
    }