问题陈述:我们正在构建一个以TypeSafeMap作为响应的库。TypeSafeMap是一个可以容纳任何类型对象的映射。现在,客户端将访问typesafemap。我们正在尝试强制执行某种级别的编译类型安全性。以下是代码和更多解释。
响应结构:
public Class Response {
private TypeSafeMap t;
public TypeSafeMap getMap() { return t; }
}
//类型安全地图
public class TypeSafeMap
{
private final static Map<String, Object> map = new HashMap<>();
public static <T> T put(String key, T value) {
if (null != key) {
return (T) map.put(key, value);
}
return (T) map;
}
@SuppressWarnings("unchecked")
public static <T> T get(PartyEnums partyEnum)
{
return (T) map.get(partyEnum.PARTY.name());
}
}
//我们向客户端公开的枚举,以获取属性和相应的字段类型
public enum PartyEnums
{
PARTY("party", new ArrayList<Party>().getClass());
private final String name;
private final Class<?> clzz; //this is the type client should access as field type
PartyEnums(String name,Class<?> clzz)
{
this.name = name;
this.clzz=clzz;
}
public Class<?> getClzz()
{
return clzz;
}
@SuppressWarnings("unchecked")
public <T> T getInstance()
{
T ins = null;
try {
ins = (T) getClzz().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return ins;
}
}
//客户端呼叫
public class ClientCall {
Object obj = TypeSafeMap.get(PartyEnums.PARTY); //No error.
String str = TypeSafeMap.get(PartyEnums.PARTY); //No error.
But we want enforce some level of compile type safety as the field type "str" and TypeSafeMap.get() type do not match.
How can we enforce compile type safety?
List<Party> party = TypeSafeMap.get(PartyEnums.PARTY);// OK.
}
TL;DR
使用当前形式的enum
无法完成此操作。有一个JEP 301:增强枚举可以解决同样的问题,但它已经被撤回了。
您(目前(强制类型安全的唯一选择是通过使用具有预定义类型常量的final
类来模拟enum
。我想它是这样的:
public final class Key<V> {
public static final Key<List<Party>> PARTY_LIST = new Key<>("party list");
public static final Key<Map<Integer, String>> PARTY_MAP = new Key<>("party map");
public static final Key<String> SOME_STRING = new Key<>("party string");
private final String name;
private Key(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
现在,我们已经准备好通过以下方式修改<T> T put(String key, T value)
(即使"枚举方法"在理论上是可能的,这显然也不安全(和<T> T get(PartyEnums partyEnum)
,使您的TypeSafeMap
真正类型安全:
public static class TypeSafeMap {
private final static Map<String, Object> MAP = new HashMap<>();
@SuppressWarnings("unchecked")
public static <T> T put(Key<T> key, T value) {
if (null != key) {
return (T) MAP.put(key.getName(), value);
}
return value;
}
@SuppressWarnings("unchecked")
public static <T> T get(Key<T> key) {
return (T) MAP.get(key.getName());
}
}
我仍然看到至少两个可能的问题:
- 多个常量可以共享同一个
name
,因此一旦使用,就可以有效地覆盖彼此(例如,可以使用enum
而不是String
( - 即使对于
null
键,put(Key<T> key, T value)
也会通过输入value
返回,这(在我看来(是故障安全的,但对调用方(他可能认为"存储"操作以某种方式成功了(具有误导性
然而,鉴于上述实现的弱点仍然符合您的初衷,因此:
这些案例会通过:
map.put(Key.JUST_STRING, "just string");
map.put(Key.PARTY_LIST, Arrays.asList(new Party()));
...
Object resultAsObject = map.get(Key.PARTY_LIST);
List<Party> resultAsList = map.get(Key.PARTY_LIST);
String resultString = map.get(Key.JUST_STRING);
但这些失败与编译时错误:
map.put(Key.PARTY_LIST, Arrays.asList(new String()));
...
String stringFromList = map.get(Key.PARTY_LIST);
请注意,Object resultAsObject = map.get(<ANYTHING>)
将始终成功,因为任何返回值(包括null(都可以表示为Object
变量