web-dev-qa-db-ja.com

Java map、key = class、value =そのクラスのインスタンス

自分が何をしたいのかわからないのですが、もしそうなら、その方法を知りたいです。基本的に、キーがクラスであるマップを作成したいと思います(Java.lang.Class)、そのエントリの値はそのクラスのインスタンスです。現在私は持っています

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

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

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

21
dnc253

Javaの型システムは、直接記述している型制約を適用するのに十分な強度がないため、これを機能させるには、安全でないキャストを実行する必要があります。または、適用する他のAPIでMapをラップする必要があります。タイプの安全性。 Guava'sClassToInstanceMap はまさにこのユースケースでそれを行い、Mapインターフェースに追加の制限を課す外部的に安全なAPIを提供します。それは動作します。 (開示:私はグアバに貢献します。)

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

14
Louis Wasserman

使用しているのは異種コンテナです。これらcanタイプトークン(すでに行っているように)とClass.cast()を正しいアプリケーションロジックで使用することにより、タイプセーフにすることができます。したがって、Class.cast()内にチェックされていないsuppressWarningがあります。 、ただし、アプリケーションロジックは正確性を保証します。

JoshBlochのEffective Java Item 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));
  }
}

メモリリークの可能性があるのは、実際には不要になったさまざまなタイプを任意に保持している場合のみです。

9
DaveFar

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

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

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

7
Peter Lawrey

同じ要件がありました。私は以下のコードを使用してそれを解決しました:

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

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

ただし、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();
}

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

0
user130076