26

やりたいことができるかどうかはわかりませんが、可能であれば、その方法を知りたいです。java.lang.Class基本的に、キーがクラス ( ) であり、そのエントリの値がそのクラスのインスタンスであるMap を作成したいと考えています。現在、私は持っています

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

ただし、これは、任意のオブジェクトをマップに配置できることを意味します。できれば作りたいので、キーにあるクラスのインスタンスだけをマップに配置できるようにします。を使用する方法はありますか? これを確実にするためのクラスのパラメータ化?

また、このようなことを行うとメモリリークが発生する可能性があることがわかりました。これがどのように起こるかを完全に理解しているかどうかはわかりません。シングルトン オブジェクトのみをマップに貼り付けますが、メモリ リークの懸念はありますか? もしそうなら、どうすればそれを防ぐことができますか?

4

5 に答える 5

17

Java の型システムは、直接記述している型制約を強制するほど強力ではありません。これを機能させるには、安全でないキャストを実行するかMap、型の安全性を強制する他の A​​PI でラップする必要があります。 Guava's ClassToInstanceMapはまさにこのユースケースに対してまさにそれを行い、Mapインターフェースに追加の制限を課して機能させる外部的に安全な API を提供します。(開示:私はGuavaに貢献しています。)

これによってメモリ リークが発生する可能性があるのは、ここで使用しているクラスがアプリケーションの存続期間中保持されない場合のみです。多くのユーザーにとって、これは問題ではありません。特に、未使用のクラスのアンロードを気にしない「サーバー側」アプリケーションを作成している場合はなおさらです。

于 2012-04-17T16:07:32.830 に答える
14

使用しているのは異種コンテナです。これら、(すでに行っているように) 型トークンを使用Class.cast()し、正しいアプリケーション ロジックを使用してタイプ セーフにすることができますClass.cast()

Josh Bloch の「Effective Java Item 29: Consider typesafe heterogeneous containers.」を読むことをお勧めします。彼の例は次のとおりです。

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

実際には不要になったさまざまな型を恣意的に保持している場合にのみ、メモリリークの可能性が見られます。

于 2012-04-17T16:24:53.470 に答える
10

コレクションを非表示にして、アクセサー メソッド経由でのみアクセスできるようにすることができます。

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

コンパイラが安全でなくても、最後のメソッドのキャストが安全であることがわかっているため、警告は無視できます。

于 2012-04-17T16:13:20.830 に答える
0

型消去のため、これは不可能です。

ただし、サブクラス化して、これを行うメソッドに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();
}

(説明のみを目的としたコード)

于 2012-04-17T16:09:25.060 に答える
0

私は同じ要件を持っていました。以下のコードを使用して解決しました:

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);
 }
}
于 2018-06-26T13:48:54.330 に答える