Ограничительные ключи в типовых безопасных гетерогенных контейнерах

Я хотел бы использовать шаблон безопасного контейнера общего типа, описанный в Joshua Bloch 's Эффективная Java, но хотела бы ограничить классы, которые могут использоваться в качестве ключей, используя enum. Ниже приведен код от Иисуса НавинаКнига

public class Favorites {

  private Map favorites = new HashMap();

  public  void putFavorite(Class type, T instance) {
    if (type == null)
      throw new NullPointerException("Type is null");
    favorites.put(type, instance);
  }

  public  T getFavorite(Class type) {
    return type.cast(favorites.get(type));
  }

}

Я хотел бы написать подобный класс, но ограничить ключи, чтобы сказать "Dog.class», а также "Cat.class», В идеале приемлемые ключи должны быть описаны перечислением, а "RestrictedFavorites» класс будет принимать членов перечисления в качестве ключей. Я'Я не уверен, смогу ли я заставить компилятор сделать все это за меня (безопасность типов, ограничение по enum, общность), но если у кого-то есть предложение, ям все уши. Ниже приведена попытка V1, которая использует проверки времени выполнения, а не проверки времени компиляции, и не является полностью удовлетворительной.

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
 * Attempt V1 At a "RestrictedFavorites" class
 */
public class RestrictedFavorites {

  public static enum RestrictedKey {

    STRING(String.class),
    INTEGER(Integer.class);

    private static Set classes;
    static {
      classes = new HashSet();
      for (RestrictedKey key: values()) {
        classes.add(key.getKlass());
      }
    }

    private final Class klass;

    RestrictedKey(Class klass) {
      this.klass = klass;
    }

    public Class getKlass() {
      return klass;
    }

    public static boolean isValidClassKey(Class klass) {
      return classes.contains(klass);
    }

  }

  private Map favorites =  new HashMap();

  //Ideally would use compile time checking
  public  void putFavorite(RestrictedKey key, T instance) {
    if (key == null) throw new NullPointerException("Type is null");
    if (!key.getKlass().equals(instance.getClass())) {
      throw new IllegalArgumentException(
          "The type of the key must match the type of the instance");
    }
    favorites.put(key.getKlass(), instance);
  }

  //Ideally would take a RestrictedKey as an argument
  public  T getFavorite(Class key) {
    if (!RestrictedKey.isValidClassKey(key)) {
      throw new IllegalArgumentException(
          "The key must be a member of RestrictedKeys");
    }
    return key.cast(favorites.get(key));
  }

}

Ниже приведены некоторые модульные тесты, чтобы убедиться, что мой класс делает примерно то, что я хочу:

public class RestrictedFavoritesTest extends TestCase {

  public void testPutFavorite() {
    RestrictedFavorites myFavorites = new RestrictedFavorites();
    myFavorites.putFavorite(RestrictedKey.INTEGER, 1);
    myFavorites.putFavorite(RestrictedKey.STRING, "hey");
    int expectedInt = myFavorites.getFavorite(Integer.class);
    assertEquals(1, expectedInt);
    String expectedString = myFavorites.getFavorite(String.class);
    assertEquals("hey", expectedString);
  }

  public void testPutFavorite_wrongType() {
    RestrictedFavorites myFavorites = new RestrictedFavorites();
    try {
      myFavorites.putFavorite(RestrictedKey.INTEGER, "hey");
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public void testPutFavorite_wrongClass() {
    RestrictedFavorites myFavorites = new RestrictedFavorites();
    try {
      myFavorites.getFavorite(Boolean.class);
    } catch (IllegalArgumentException expected) {}
  }

}

Ответы на вопрос(1)

Ваш ответ на вопрос