Метод enum, который возвращает перечисления определенного интерфейса - PullRequest
0 голосов
/ 08 ноября 2011

У меня есть следующий интерфейс

public interface DeviceKey {
    String getKey();
}

У меня также есть различные перечисления, которые расширяют этот интерфейс.

В классе, который содержит все перечисления, я хочу, чтобы метод, основанный на строке (ключе), мог вернуть перечисление, соответствующее этой строке. Строка связана с перечислением, но это не имя. Мой класс и перечисление могут выглядеть так:

public class Settings {
    private static final Map<String, DeviceKey> lookupAll = Maps.newHashMap();
    static {
        lookupAll.putAll(SmartSetting.lookup);
        // Plus a lot more similar to these
    }

    public static DeviceKey valueOfAnyKey(String key) {
        return lookupAll.get(key);
    }

    public enum SmartSetting implements DeviceKey {
        STATUS("smart_status");

        private static final Map<String, SmartSetting> lookup = EnumUtil.addAll(SmartSetting.class);
        private final String key;

        SmartEncryptionSetting(String key) {
            this.key = key;
        }

        @Override
        public String getKey() {
            return key;
        }
    }
}

Текущая реализация valueOfAnyKey() возвращает DeviceKey, который, конечно, не является перечислением. Что я должен сделать, чтобы valueOfAnyKey() возвращал перечисление типа DeviceKey?

EnumUtil:

private static class EnumUtil {

    public static <T extends Enum<T> & DeviceKey> Map<String, T> addAll(Class<T> theClass) {
        final Map<String, T> retval = new HashMap<String, T>();
        for(T s : EnumSet.allOf(theClass)) {
            retval.put(s.getKey(), s);
        }
        return retval;
    }
}

Ответы [ 3 ]

0 голосов
/ 09 ноября 2011

В Java метод может возвращать только один тип.Вы не можете вернуть DeviceKey "и" Enum

0 голосов
/ 17 ноября 2011

Ну, после работы с этим какое-то время коллега нашел какое-то решение.Изменений в перечислении очень мало, а также необходимо внести некоторые изменения, когда вызывается valueOfAnyKey().Так что теперь мы можем вернуть DeviceKey, который, как мы знаем, является Enum.

public class Settings {
    private static final Map<String, Enum<?>> lookupAll = Maps.newHashMap();
    static {
        lookupAll.putAll(SmartSetting.lookup);
        // Plus a lot more similar to these
    }

    public static <T extends Enum<T> & DeviceKey> T valueOfAnyKey(String name) {
        return (T) lookupAll.get(name);
    }

    public enum SmartSetting implements DeviceKey {
        STATUS("smart_status");

        private static final Map<String, SmartSetting> lookup = EnumUtil.addAll(SmartSetting.class);
        private final String key;

        SmartEncryptionSetting(String key) {
            this.key = key;
        }

        @Override
        public String getKey() {
            return key;
        }
    }
}

Поиск настроек теперь выполняется следующим образом.Ни у IntelliJ, ни у eclipse нет проблем с опущением <T>, но компилятор Oracle настаивает на его наличии.

T setting = DeviceSetting.<T>valueOfAnyKey("settingName);

Теперь <T> должен быть определен на уровне метода или класса.Если он определен на уровне метода, то иногда вы также будете испытывать проблемы с компилятором Oracle, поэтому рекомендуется вместо этого добавить определение в класс.

Либо:

public class SomeClass <T extends Enum<T> & DeviceKey> {
    ....
}

, либо

public class SomeClass {
    public <T extends Enum<T> & DeviceKey> void aMethod() {
        ...
    }
}

После всего этого мы все еще не можем понять, какой тип Enum мы получаем, и для использования setting (типа T) нам нужно привести его с помощью SmartSetting.class.cast(setting).Мы обсудили, дает ли это нам лучшее решение, чем предложенное Рэй Тайком, которое также было нашей первой реализацией, и пришли к выводу, что мы предоставляем немного больше подробностей о том, что возвращается, но с точки зрения вызывающих сторонВы всегда должны будете выполнять приведение класса.

0 голосов
/ 08 ноября 2011

может быть что-то вроде этого:

import java.util.*;
interface Key {
    String get();
}
class Enums {
    enum Color implements Key {
        r("foo"), g("bar"), b("baz");
        Color(String key) {
            this.key = key;
        }
        public String get() {
            return key;
        }
        final String key;
    }
    enum Day implements Key {
        m("quux"), t("fred"), w("hozer");
        Day(String key) {
            this.key = key;
        }
        public String get() {
            return key;
        }
        final String key;
    }
    static final Map<String, Enum> map = new LinkedHashMap<String, Enum>();
    static {
        for (Color c : Color.values())
            map.put(c.get(), c);
        for (Day d : Day.values())
            map.put(d.get(), d);
    }
}
public class Main {
    public static void main(String[] args) {
        for (Enums.Color c : Enums.Color.values())
            System.out.println(c+" "+c.get()+" "+Enums.map.get(c.get()));
        for (Enums.Day d : Enums.Day.values())
            System.out.println(d+" "+d.get()+" "+Enums.map.get(d.get()));
    }
}
...