Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Latent typing using interface and Enum

I have an IDevice interface and two enum realizations of this interface: AndroidDevice and IosDevice. The issue is: I want to use latent typing and call values() method on an interface reference:

private IDevice getDeviceByReadableName(String versionInXml, IDevice devices) {
    for(IDevice device : devices.values()){
    //...

So I have to add public IDevice[] values(); to my interface:

public interface IDevice {
     //...
     public IDevice[] values();
}

But it doesn't work. Eclipse asks me to remove static modifiers from AndroidDevice(...)


Please:

  1. Explain to me why it doesn't work?
  2. What is the best solution to this problem, should I use reflection instead?
like image 914
Rudziankoŭ Avatar asked Oct 20 '15 15:10

Rudziankoŭ


2 Answers

Reason why it doesn't work is because a static values() method is implicitly defined for every enum.

public enum IOS {

    //Compiler raises an error that values() method is already defined.
    public IOS[] values(){

    }
}

So, when you have a static method already defined, you can't add a new instance level method with same signature.

The easiest way to fix it is to use a different method name.

public interface IDevice {

    IDevice[] allvalues();
}

public enum IOS implements IDevice{

    IPHONE, IPAD;

    @Override
    public IDevice[] allvalues() {
        //return array of iOS devices;
    }
}
like image 106
Mohit Avatar answered Sep 22 '22 10:09

Mohit


Use a type intersection:

private <T extends Enum<T> & IDevice> T getDeviceByReadableName(String versionInXml, Class<T> deviceClass) {
    for (T device : deviceClass.getEnumConstants()) {
        if (<some-condition>)
            return device;
    }
    return null;
}

The bound to Enum<T> ensures that deviceClass.getEnumConstants() will return values, and the bound to & IDevice ensures you'll get an IDevice back.

Call it like:

enum IosDevice implements IDevice {
    iPhone, iPad, MacBook;
}

IDevice d = getDeviceByReadableName("<foo/>", IosDevice.class);
like image 32
Bohemian Avatar answered Sep 19 '22 10:09

Bohemian