我知道这听起来有点疯狂,但现在确实如此。我有一个代表一组不同属性的枚举类型。每个都可能只是一个字符串,但强制执行某种类型的安全性会很好。因此,基本上检查与每个枚举值关联的类型,如果不匹配则抛出异常。我想这可以通过实例来完成,但我很好奇是否有另一种方法可以在没有instanceof的情况下执行此操作。我知道这可能不可能,但我很好奇。
编辑,我创建了一个新示例,我认为这说明了我要求的更好:
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);
}
}
稍后我想要发生这种情况:
CmisProperties props = new CmisProperties();
/* This causes a compile time exception */
props.setProperty(CmisPropEnum.CreationDate, "foobar" );
/* This I want to be ok, because the type matches that in the enum */
props.setProperty(CmisPropEnum.CreationDate, new Date() );
答案 0 :(得分:1)
查看Josh Bloch的 Effective Java ,第29项,其中他描述了一个他称之为收藏夹的“类型安全异构容器”。 API是
public class Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
我认为它符合您的需求(可能更改名称???)。你可以打电话给
favorite.putFavorite(Name.getClass(), "Fred");
favorite.putFavorite(ADate.getClass(), new Date(1234));
以后
Date date = favorite.getFavorite(ADate.getClass());
答案 1 :(得分:1)
正如已经提到的那样,无可争议的,你需要基于类型(即泛型)的类具有可变性。这是您示例的相应通用版本:
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
答案 2 :(得分:0)
枚举不能是通用的,所以我们需要一个普通的类
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() {...}
}
然后set / get属性方法可以有更强的静态类型检查:
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
请注意,propMap
中的每个条目都有一个Prop<X>
的密钥,X
的值为X
,而X
可能与条目不同条目。我们无法在Java中对Map
表达这种约束;但约束确实是由app逻辑强制执行的(即setProperty()
只插入这样的条目)
在getProperty
中,我们必须取消未经检查的警告。这是合理的,因为我们知道密钥的值必须是T
类型,这是由于前面提到的约束。避免明确禁止警告的一个技巧是Class.cast()
public <T> T getProperty(Prop<T> key)
{
return key.getClassT().cast( propMap.get(key) );
}
但这只是一个技巧,因为基本上我们将@SupressWarnings移到了Class.cast()
。这是性能和语义清晰度方面的更糟糕版本。