Подтвердить что ты не робот

Карта Java, ключ = класс, value = экземпляр этого класса

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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);
}

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

Ответ 3

Что вы используете, это разнородный контейнер. Эти могут создавать типы с помощью токенов типа (как вы уже это делали) и Class.cast() с правильной логикой приложения. Таким образом, в Class.cast() есть непроверенное подавление предупреждения, но логика приложения гарантирует правильность.

Советую вам прочитать Josh Bloch Эффективная Java. Пункт 29: Рассмотрите типы гетерогенных контейнеров. Его пример:

// 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));
  }
}

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

Ответ 4

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

Однако вы можете подклассом 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();
}

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