Java map, key = class, value = экземпляр этого класса

Я не уверен, что я хочу сделать, это возможно, но если это так, я хочу узнать как. В принципе, я хочу создать карту, где ключ-класса (java.lang.Class), и значение для этой записи является экземпляром этого класса. В настоящее время у меня

private Map<Class<?>, Object> myMap = new HashMap<Class<?>, Object>();

однако, это означает, что любой объект может быть помещен в карте. Если это возможно, я хочу сделать это, поэтому на карте можно разместить только экземпляр класса в ключе. Есть ли способ использовать ? параметризация класса для обеспечения это?

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

5 ответов


система типов Java просто недостаточно сильна, чтобы применить ограничение типа, которое вы описываете напрямую, и вам нужно будет сделать некоторые небезопасные броски, чтобы сделать эту работу-или обернуть Map в каком-то другом API, который обеспечивает безопасность типа. гуава это!--5--> ClassToInstanceMap делает именно это для именно этого случая использования, предоставляя внешне безопасный API, который налагает дополнительные ограничения на Map интерфейс, чтобы заставить его работать. (Раскрытие информации: я содействую Гуава.)

единственный раз, когда это может вызвать утечку памяти, если есть некоторые классы, которые вы используете здесь, которые не будут сохранены для жизни приложения. Это не беспокоит многих пользователей, особенно если вы пишете приложение "на стороне сервера", которое не беспокоится о выгрузке неиспользуемых классов.


вы можете скрыть коллекцию и разрешить доступ к ней только с помощью методов доступа.

private final Map<Class, Object> myMap = new HashMap<Class, Object>();

public <T> void putMap(Class<T> tClass, T t) {
     myMap.put(tClass, t);
}

@SuppressWarnings("unchecked")
public <T> T getMap(Class<T> tClass) {
    return (T) myMap.get(tClass);
}

предупреждение можно игнорировать, поскольку вы знаете, что приведение в последнем методе безопасно, даже если компилятор этого не делает.


что вы используете это неоднородная контейнер. Эти can сделайте typesafe, используя маркеры типа (как вы уже делаете) и Class.cast() с правильной логикой приложения: таким образом, в Class.cast(), но логика приложения гарантирует правильность.

я советую вам прочитать эффективный Java-элемент 29 Джоша Блоха: рассмотрите гетерогенные контейнеры typesafe. Его пример есть:

// Typesafe heterogeneous container pattern - implementation
public class Favorites {
  private Map<Class<?>, Object> favorites =
    new HashMap<Class<?>, Object>();

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

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

Я вижу только возможность утечки памяти если вы держите произвольно много разных типов, которые вам на самом деле больше не нужны.


Это невозможно из-за стирания типа.

однако вы можете подкласс HashMap и запишите некоторую логику в put метод, который сделает это для вас:

public void put(K key, V value) {

    if  ( // value is an instance of key using .getClass()) { 
        super.put(key, value)
    }
    throw new Exception();
}

(код только для иллюстрации)


У меня было такое же требование. Я решил его, используя следующий код:

interface Service { }

class ServiceCache {
private HashMap<Class<? extends Service>, Service> services;

public ServiceCache() {
    services = new HashMap<>();
}

public <T extends Service> T getService(Class<T> service) {
    if (services.containsKey(service))
        return (T) services.get(service);
    return null;
}

public <T extends Service> void addService(T service, Class<? extends Service> serviceInterface) {
    services.put(serviceInterface, service);
 }
}