使用枚举键和不同值类型进行映射
Map with enum key and different value types
我想在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) {
//...
}
将从该映射中获取值并将其转换为对应类型 class?
您的地图定义需要
Map< KeyType, ?> map = new EnumMap<>(KeyType.class);
如果您将 Object
指定为通用类型,则只允许 Object
的实际实例,而不是子类型。
我不相信有任何直接、通用的方式(没有双关语意)来做你想做的事。您需要创建一些映射函数,根据枚举将对象转换为正确的类型。
更新!!!:
考虑到这一点:
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));
}
你不能用枚举来做到这一点。但是您可以编写一个 "fake" 枚举(Java 代码在 Java 1.5 之前使用私有构造函数和 public 静态实例的方式),并为每个枚举附加一个泛型类型常量:
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));
}
}
我想在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) {
//...
}
将从该映射中获取值并将其转换为对应类型 class?
您的地图定义需要
Map< KeyType, ?> map = new EnumMap<>(KeyType.class);
如果您将 Object
指定为通用类型,则只允许 Object
的实际实例,而不是子类型。
我不相信有任何直接、通用的方式(没有双关语意)来做你想做的事。您需要创建一些映射函数,根据枚举将对象转换为正确的类型。
更新!!!: 考虑到这一点:
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));
}
你不能用枚举来做到这一点。但是您可以编写一个 "fake" 枚举(Java 代码在 Java 1.5 之前使用私有构造函数和 public 静态实例的方式),并为每个枚举附加一个泛型类型常量:
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));
}
}