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