Search code examples
javagenericsparametersenums

How do I enforce an (Enum) interface implementation in an overridden method parameter in Java?


I'm having issues enforcing an (Enum) interface implementation as an overridden method parameter in Java. Relevant (simplified) code that shows what I'm trying to do:

public interface AnimalSound {}
public enum CowSound implements AnimalSound {
    MOO, BOO
}
public interface Animal {
    <T extends AnimalSound> T getSound();
    <T extends AnimalSound> void setSound(T sound);
}
public class Cow implements Animal {
    @Override
    public CowSound getSound() {
        return CowSound.BOO;
    }

    @Override
    public <T extends AnimalSound> void setSound(T sound) {
        if(sound.getClass() != CowSound.class) throw new IllegalArgumentException("Only works with cow sounds!");
    }
}

The #getSound works just fine (when I suppress the IDE Unchecked overriding warning). The #setSound however doesn't enforce a CowSound here, and I'd rather the IDE/compiler enforces this than throwing an exception during runtime.

What I -want- to do with the #setSound method is something like:

@Override
public void setSound(CowSound sound) {//set a sound}

This however doesn't override the interface. Is there a better/other way to enforce the CowSound implementation here instead of accepting any implementation of AnimalSound and throw a runtime exception?


Solution

  • The problem is that you're making the individual methods generic, while you need to make the type generic. So, you need to use:

    public interface Animal<T extends AnimalSound> {
        T getSound();
        void setSound(T sound);
    }
    

    and

    public class Cow implements Animal<CowSound> {
        @Override
        public CowSound getSound() {
            return CowSound.BOO;
        }
    
        @Override
        public void setSound(CowSound sound) {
            // ...
        }
    }