【问题标题】:Map with enum key and different value types具有枚举键和不同值类型的映射
【发布时间】:2015-06-27 13:10:14
【问题描述】:

我想在 Java 中定义映射,哪些键是枚举,值的类型取决于键。例如,假设我们有以下枚举类型:

enum KeyType {
        HEIGHT(Integer.class),
        NAME(String.class),
        WEIGHT(Double.class)
       // constructor and getter for Class field

}

还有一些地图:

Map< KeyType, Object > map = new EnumMap<>(KeyType.class);

有没有简单安全的写泛型方法的方法:

public < T > T get(KeyType key) {
//...
}

那将从该映射中获取值并将其转换为与类型类对应的?

【问题讨论】:

  • 对不起,这个方法是EnumMap提供的,我理解错了吗?
  • 我相信没有,因为在编译时它不知道会返回哪种类型——你没有声明它,而是作为参数传递。
  • 在使用get这个方法时,你认为编译器可以根据什么信息推断出T的正确类型?提示:没有这样的信息。结论,您可以取回正确类型的对象,但方法不能是泛型的。这会自动导致@xerx593 的评论:改用Map.get(...)
  • 您需要一个使用T 的参数。但由于枚举不允许类型参数,你将不得不使用一个类或其他东西。

标签: java generics dictionary collections enums


【解决方案1】:

更新!!!: 考虑到这一点:

enum KeyType {

    //your enums ...
    private final Class val;

    //constructor ...

    //and generic(!) access to the class field:
    <T> Class<T> val() {
        return val;
    }
}

...这是可能的:

public <T> T get(KeyType key) {
    return (T) key.val().cast(map.get(key));
}

【讨论】:

【解决方案2】:

您的地图定义需要是

Map< KeyType, ?> map = new EnumMap<>(KeyType.class);

如果您将Object 指定为泛型类型,则只允许Object 的实际实例,而不是子类型。

我不相信有任何直接、通用的方式(没有双关语)来做你想做的事。您需要创建一些映射函数,根据枚举将对象转换为正确的类型。

【讨论】:

    【解决方案3】:

    你不能用枚举来做到这一点。但是您可以编写一个“假”枚举(Java 代码在 Java 1.5 之前使用私有构造函数和公共静态实例的方式),并为每个常量附加一个泛型类型:

    import java.io.Serializable;
    import java.util.Map;
    
    public final class KeyType<T>
    implements Serializable {
        private static final long serialVersionUID = 1;
    
        public static final KeyType<Integer> HEIGHT =
            new KeyType<>("HEIGHT", Integer.class);
    
        public static final KeyType<String> NAME =
            new KeyType<>("NAME", String.class);
    
        public static final KeyType<Double> WEIGHT =
            new KeyType<>("WEIGHT", Double.class);
    
        private static final KeyType<?>[] allValues = {
            HEIGHT, NAME, WEIGHT
        };
    
        /** @serial */
        private final String name;
    
        /** @serial */
        private final Class<T> type;
    
        private KeyType(String name,
                        Class<T> type) {
            this.name = name;
            this.type = type;
        }
    
        public String name() {
            return name;
        }
    
        public Class<T> getType() {
            return type;
        }
    
        @Override
        public String toString() {
            return name();
        }
    
        public static KeyType<?>[] values() {
            return allValues.clone();
        }
    
        public static KeyType<?> valueOf(String name) {
            for (KeyType<?> value : allValues) {
                if (value.name.equals(name)) {
                    return value;
                }
            }
            throw new IllegalArgumentException("No such value: \"" + name + "\"");
        }
    
        @Override
        public boolean equals(Object obj) {
            return (obj instanceof KeyType &&
                this.name.equals(((KeyType<?>) obj).name));
        }
    
        @Override
        public int hashCode() {
            return name.hashCode();
        }
    
        public T getValue(Map<KeyType<?>, ?> map) {
            return type.cast(map.get(this));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-08-01
      • 2019-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多