EnumSet as a parameter in generic Interface

Vatsal Prakash :

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)

Ravindra Ranwala :

Parameterized types are invariant, hence EnumSet<FetchMode> is NOT the same as EnumSet<?>. 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 subtypes of enum. This idiom supports that.

What you have to do is declare a generic interface 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) {

    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=169535&siteId=1