Карта Java со значениями, ограниченными параметром типа ключа

Есть ли способ в Java иметь карту, где параметр типа значения привязан к типу параметра ключа? Я хочу написать следующее:

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

То есть, я могу сохранить любое значение по умолчанию для объекта Class, если тип значения совпадает с типом объекта classа. Я не понимаю, почему это не должно быть разрешено, поскольку я могу гарантировать, что при настройке / получении значений правильные типы.

EDIT: Благодаря cletus за его ответ. Мне действительно не нужны параметры типа на самой карте, так как я могу обеспечить согласованность методов, которые получают / устанавливают значения, даже если это означает использование немного уродливых бросков.

Вы не пытаетесь реализовать типичную разнородную модель контейнера Джошуа Блоха? В основном:

 public class Favorites { private Map, Object> favorites = new HashMap, Object>(); public  void setFavorite(Class klass, T thing) { favorites.put(klass, thing); } public  T getFavorite(Class 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 (2-е издание) и этой презентации .

Нет, вы не можете сделать это напрямую. Вам нужно написать class-оболочку вокруг Map чтобы обеспечить, чтобы Object был instanceof classа.

Вопрос и ответы заставили меня придумать это решение: Типовая карта объектов . Вот код. Прецедент:

 import static org.junit.Assert.*; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class TypedMapTest { private final static TypedMapKey KEY1 = new TypedMapKey( "key1" ); private final static TypedMapKey> KEY2 = new TypedMapKey>( "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 list = new ArrayList (); map.set( KEY2, list ); List valueList = map.get( KEY2 ); assertEquals( list, valueList ); } } 

Ключевой class:

 public class TypedMapKey { 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 { private Map delegate; public TypedMap( Map delegate ) { this.delegate = delegate; } public TypedMap() { this.delegate = new HashMap(); } @SuppressWarnings( "unchecked" ) public  T get( TypedMapKey key ) { return (T) delegate.get( key ); } @SuppressWarnings( "unchecked" ) public  T remove( TypedMapKey key ) { return (T) delegate.remove( key ); } public  void set( TypedMapKey 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> 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 keySet() { return delegate.keySet(); } public Object put( Object key, Object value ) { return delegate.put( key, value ); } public void putAll( Map m ) { delegate.putAll( m ); } public Object remove( Object key ) { return delegate.remove( key ); } public int size() { return delegate.size(); } public Collection values() { return delegate.values(); } } 

T как тип должен быть определен в общем экземпляре classа. Следующий пример работает:

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

В качестве альтернативы вы можете использовать ответ Павла Томблина и обернуть Map своим собственным объектом, который будет применять этот тип дженериков.

  • В чем проблема с алгоритмом обнаружения времени выполнения Apache Commons Logging
  • Что означает «com.developer.application»?
  • Я не могу заставить webRDP работать
  • SQLException: Не найдено подходящего драйвера для jdbc: derby: // localhost: 1527
  • Создание двух исполняемых банок с использованием maven-assembly-plugin
  • Как найти n-ое появление символа в строке?
  • BitSet с целым числом и длительностью
  • Как создать runnable JAR в IntelliJ, как и в Eclipse
  • Как сделать AWT Button () и использовать ImageIcon (), Icon ()?
  • Java Bouncing Ball
  • сжатие и декомпрессия строковых данных в java
  • Давайте будем гением компьютера.