【问题标题】:An enum method that returns enums of specific interface返回特定接口枚举的枚举方法
【发布时间】:2011-11-08 10:42:57
【问题描述】:

我有如下界面

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;
    }
}

【问题讨论】:

    标签: java generics interface enums enumeration


    【解决方案1】:

    在 Java 中,一个方法只能返回一种类型。你不能让它返回DeviceKey“和”Enum

    【讨论】:

    • 我选择了这个作为正确答案,尽管最终代码是按照我在答案中写的那样实现的。我这样做是因为查看原始问题,这是正确的答案。一开始无法得到我想要的东西。
    【解决方案2】:

    可能是这样的:

    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()));
        }
    }
    

    【讨论】:

    • 这将返回一个枚举,但它不会提供对从 DeviceKey 接口实现的方法的访问权限。
    • 静态最终映射 map = new LinkedHashMap(); // 改为这样做
    • 那么它是一个Key,它不能被使用,例如。在 switch 语句中。我需要的是返回特定类型的枚举(我的接口)。我开始认为这是不可能的,即使使用泛型。
    • 使用枚举并将其转换为键。
    【解决方案3】:

    好吧,经过一段时间的研究,一位同事找到了解决方案。枚举的更改很少,并且在调用 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 都没有遗漏 &lt;T&gt; 的问题,但 Oracle 编译器坚持认为它存在。

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

    &lt;T&gt;,现在应该在方法或类级别定义。如果它是在方法级别定义的,那么您有时也会遇到 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) 对其进行转换。 我们已经讨论过这是否真的为我们提供了比 Ray Tayek 建议的解决方案更好的解决方案,这也是我们的第一个实现,结论是我们提供了更多关于返回内容的细节,但从调用者的角度来看您将始终需要进行班级演员表。

    【讨论】:

      猜你喜欢
      • 2013-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-09
      • 1970-01-01
      相关资源
      最近更新 更多