Java 是否可以有一个只允许基于键的值类型的映射?
我知道这听起来有点疯狂,但就是这样。我有一个枚举类型,它表示一组不同的属性。每一个都可以只是一个字符串,但最好强制某种类型的类型安全性。因此,基本上检查与每个枚举值关联的类型,如果不匹配,则抛出异常。我想这可以通过的实例来实现,但我很好奇是否有其他方法可以在没有实例的情况下实现这一点。我知道这可能不可能,但我很好奇 编辑,我创建了一个新的示例,我认为它更好地说明了我的要求:Java 是否可以有一个只允许基于键的值类型的映射?,java,Java,我知道这听起来有点疯狂,但就是这样。我有一个枚举类型,它表示一组不同的属性。每一个都可以只是一个字符串,但最好强制某种类型的类型安全性。因此,基本上检查与每个枚举值关联的类型,如果不匹配,则抛出异常。我想这可以通过的实例来实现,但我很好奇是否有其他方法可以在没有实例的情况下实现这一点。我知道这可能不可能,但我很好奇 编辑,我创建了一个新的示例,我认为它更好地说明了我的要求: public class CmisProperties { public enum CmisPropEnum{
public class CmisProperties {
public enum CmisPropEnum{
Name (PropertyIds.NAME, new String() ),
CreatedBy (PropertyIds.CREATED_BY, new String() ),
CreationDate (PropertyIds.CREATION_DATE, new Date() ),
LastModifiedBy (PropertyIds.LAST_MODIFIED_BY, new String() ),
LastModificationDate (PropertyIds.LAST_MODIFICATION_DATE, new Date() ),
ChangeToken (PropertyIds.CHANGE_TOKEN, new String() );
private String propId;
CmisPropEnum ( String propId , Object templateObject ){
this.propId = propId;
}
public <T> String getPropId(){
return propId;
}
}
private Map<CmisPropEnum, Object> propertyMap = new HashMap<CmisPropEnum, Object>();
public Object getProperty(CmisPropEnum propEnum){
return propertyMap.get(propEnum.getPropId());
}
public void setProperty( CmisPropEnum propEnum, Object value){
propertyMap.put(propEnum, value);
}
}
查看Josh Bloch的有效Java,第29项,其中他描述了一个他称之为收藏夹的“类型安全异构容器”。API是
public class Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
后来
Date date = favorite.getFavorite(ADate.getClass());
枚举不能是泛型的,所以我们需要一个普通类
public class Prop<T>
{
// some predefined props
static public final Prop<String> NAME = new Prop<>("Name", String.class);
...
public Prop(String name, Class<T> type) // it's ok, anyone can create new kind of Prop
{...}
Class<T> getClassT() {...}
}
请注意,对于某些X
,propMap
中的每个条目都有一个键Prop
和一个值X
,并且X
可以因条目而异。我们无法用Java在Map
上真正表达这种约束;但应用程序逻辑确实强制执行了该约束(即,setProperty()
仅插入此类条目)
在getProperty
中,我们必须抑制未检查的警告。这是合理的,因为我们知道由于前面提到的限制,键的值必须是T
类型。避免显式抑制警告的一个技巧是通过Class.cast()
public T getProperty(道具键)
{
return key.getClassT().cast(propMap.get(key));
}
但这只是一个技巧,因为本质上我们将@superswarnings移动到
Class.cast()
。这是一个性能和语义清晰性较差的版本。正如Unreputable所提到的,您需要基于类型(即泛型)的类具有可变性。这是示例的相应通用版本:
public class Properties {
public static class Property<E> {
private Property(String name) { this.name = name; }
private final String name;
public String getName() { return name; }
}
public static final Property<String> NAME = new Property<String>("name");
// ... other properties
private Map<Property<?>, Object> propertyMap =
new HashMap<Property<?>, Object>();
@SuppressWarnings("unchecked")
public <E> E getProperty(Property<E> property){
return (E) propertyMap.get(property);
}
public <E> void setProperty(Property<E> property, E value){
propertyMap.put(property, value);
}
}
p、 请注意,在这段代码中,每种类型只能有一个键值对,因为类是键。可以吗?请注意,如果
Name
和ADate
是类(正如它们的大写似乎暗示的那样),那么获取它们各自的类对象的正确方法将是Name.class
和ADate.class
。否则,这看起来像是OP所要求的。要回答user9493000,是的,我实际上在寻找一个允许多个键(如果您所说的键是类型)对的解决方案。很抱歉,我的示例代码不清楚。Name和ADate只是枚举。我给它们命名是为了清楚地知道我希望它们与什么类型相关。我想我本可以让阿黛特·巴黛特·巴黛特·巴黛特戴上戒指。。。等等但是非常感谢您的输入。如果您不使用类
对象,那么它没有任何用途。仅使用泛型就可以获得相同的静态类型,但不能让它执行编译时异常。至少,我想不出一个办法。如果在将值放入propertyMap之前让setProperty()方法检查value.getClass()与合法值,则可能会出现运行时异常。
public class Prop<T>
{
// some predefined props
static public final Prop<String> NAME = new Prop<>("Name", String.class);
...
public Prop(String name, Class<T> type) // it's ok, anyone can create new kind of Prop
{...}
Class<T> getClassT() {...}
}
private Map< Prop,Object > propMap = new HashMap<>();
public <T> void setProperty(Prop<T> key, T value){
propMap.put(key, value);
}
@SuppressWarnings("unchecked")
public <T> T getProperty(Prop<T> key)
{
return (T)propMap.get(key);
}
setProperty(Prop.NAME, new Integer(1)); // fail
int x = getProperty(Prop.NAME); //fail
public <T> T getProperty(Prop<T> key)
{
return key.getClassT().cast( propMap.get(key) );
}
public class Properties {
public static class Property<E> {
private Property(String name) { this.name = name; }
private final String name;
public String getName() { return name; }
}
public static final Property<String> NAME = new Property<String>("name");
// ... other properties
private Map<Property<?>, Object> propertyMap =
new HashMap<Property<?>, Object>();
@SuppressWarnings("unchecked")
public <E> E getProperty(Property<E> property){
return (E) propertyMap.get(property);
}
public <E> void setProperty(Property<E> property, E value){
propertyMap.put(property, value);
}
}
Properties p = new Properties();
p.setProperty(Properties.NAME, "a string"); // only strings allowed for NAME
String s = p.getProperty(Properties.NAME); // can only get strings for NAME