Java地图的值由键的types参数限制

有没有一种方法在Java中有一个映射的值的types参数绑定到一个键的types参数? 我想写的东西是这样的:

public class Foo { // This declaration won't compile - what should it be? private static Map<Class<T>, T> defaultValues; // These two methods are just fine public static <T> void setDefaultValue(Class<T> clazz, T value) { defaultValues.put(clazz, value); } public static <T> T getDefaultValue(Class<T> clazz) { return defaultValues.get(clazz); } } 

也就是说,我可以将任何默认值存储在Class对象中,只要该值的types与Class对象的types匹配即可。 我不明白为什么这不应该被允许,因为我可以确保何时设置/获取值的types是正确的。

编辑:谢谢cletus他的答案。 我实际上并不需要地图本身的types参数,因为我可以确保get / set方法的一致性,即使这意味着使用一些稍微丑陋的转换。

你不是想要实现Joshua Bloch的types安全的异构容器模式吗? 基本上:

 public class Favorites { private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>(); public <T> void setFavorite(Class<T> klass, T thing) { favorites.put(klass, thing); } public <T> T getFavorite(Class<T> klass) { return klass.cast(favorites.get(klass)); } public static void main(String[] args) { Favorites f = new Favorites(); f.setFavorite(String.class, "Java"); f.setFavorite(Integer.class, 0xcafebabe); String s = f.getFavorite(String.class); int i = f.getFavorite(Integer.class); } } 

从有效的Java(第二版)和这个演示 。

不,你不能直接做。 您需要围绕Map<Class, Object>编写一个包装类来强制该Object将是instanceof Class。

这个问题和答案让我想出了这个解决scheme: types安全的对象映射 。 这是代码。 testing用例:

 import static org.junit.Assert.*; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class TypedMapTest { private final static TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" ); private final static TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" ); @Test public void testGet() throws Exception { TypedMap map = new TypedMap(); map.set( KEY1, null ); assertNull( map.get( KEY1 ) ); String expected = "Hallo"; map.set( KEY1, expected ); String value = map.get( KEY1 ); assertEquals( expected, value ); map.set( KEY2, null ); assertNull( map.get( KEY2 ) ); List<String> list = new ArrayList<String> (); map.set( KEY2, list ); List<String> valueList = map.get( KEY2 ); assertEquals( list, valueList ); } } 

主要类别:

 public class TypedMapKey<T> { private String key; public TypedMapKey( String key ) { this.key = key; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ( ( key == null ) ? 0 : key.hashCode() ); return result; } @Override public boolean equals( Object obj ) { if( this == obj ) { return true; } if( obj == null ) { return false; } if( getClass() != obj.getClass() ) { return false; } TypedMapKey<?> other = (TypedMapKey<?>) obj; if( key == null ) { if( other.key != null ) { return false; } } else if( !key.equals( other.key ) ) { return false; } return true; } @Override public String toString() { return key; } } 

TypedMap.java:

 import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class TypedMap implements Map<Object, Object> { private Map<Object, Object> delegate; public TypedMap( Map<Object, Object> delegate ) { this.delegate = delegate; } public TypedMap() { this.delegate = new HashMap<Object, Object>(); } @SuppressWarnings( "unchecked" ) public <T> T get( TypedMapKey<T> key ) { return (T) delegate.get( key ); } @SuppressWarnings( "unchecked" ) public <T> T remove( TypedMapKey<T> key ) { return (T) delegate.remove( key ); } public <T> void set( TypedMapKey<T> key, T value ) { delegate.put( key, value ); } // --- Only calls to delegates below public void clear() { delegate.clear(); } public boolean containsKey( Object key ) { return delegate.containsKey( key ); } public boolean containsValue( Object value ) { return delegate.containsValue( value ); } public Set<java.util.Map.Entry<Object, Object>> entrySet() { return delegate.entrySet(); } public boolean equals( Object o ) { return delegate.equals( o ); } public Object get( Object key ) { return delegate.get( key ); } public int hashCode() { return delegate.hashCode(); } public boolean isEmpty() { return delegate.isEmpty(); } public Set<Object> keySet() { return delegate.keySet(); } public Object put( Object key, Object value ) { return delegate.put( key, value ); } public void putAll( Map<? extends Object, ? extends Object> m ) { delegate.putAll( m ); } public Object remove( Object key ) { return delegate.remove( key ); } public int size() { return delegate.size(); } public Collection<Object> values() { return delegate.values(); } } 

作为types的T必须在类实例中一般地定义。 以下示例工作:

 public class Test<T> { private Map<Class<T>, T> defaultValues; public void setDefaultValue(Class<T> clazz, T value) { defaultValues.put(clazz, value); } public T getDefaultValue(Class<T> clazz) { return defaultValues.get(clazz); } } 

或者,您可以使用Paul Tomblin的答案,并用您自己的对象来包装Map ,这将强制执行这种types的generics。