Java map, key = class, value = instance of that cl

2019-01-17 12:14发布

I'm not sure what I want to do is possible, but if it is, I want to find out how. Basically, I want to create a Map where the key is a class (java.lang.Class), and value for that entry is an instance of that class. Currently I have

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

However, this means any Object can be placed in the Map. If it is possible, I want to make it, so only an instance of the class in the key can be placed in the map. Is there any way to use the ? parametrization on the Class to ensure this?

Also, I found there could be a possible memory leak when doing something like this. I'm not sure I fully understand how this happens. I will only be sticking singleton objects into the map, so would there still be concern for a memory leak? If so, how do I prevent it?

5条回答
做个烂人
2楼-- · 2019-01-17 12:37

You can hide the collection and only allow it to be accessed via accessor methods.

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

The warning can be ignored as you know the cast in the last method is safe even if the compiler does not.

查看更多
祖国的老花朵
3楼-- · 2019-01-17 12:50

Java's type system is simply not strong enough to enforce the type constraint you're describing directly, and you'll need to do some unsafe casts to make this work -- or wrap the Map in some other API that enforces the type safety. Guava's ClassToInstanceMap does just that for exactly this use case, providing an externally safe API that imposes additional restrictions on the Map interface to make it work. (Disclosure: I contribute to Guava.)

The only time this can cause a memory leak is if there's some classes you're using here that would not be retained for the life of the application. This isn't a concern for many users, especially if you're writing a "server side" application that isn't as concerned about unloading unused classes.

查看更多
4楼-- · 2019-01-17 12:51

This isn't possible due to type erasure.

However, you could subclass HashMap and write some logic into the put method which will do this for you:

public void put(K key, V value) {

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

(Code for illustrative purposes only)

查看更多
Anthone
5楼-- · 2019-01-17 12:51

I had the same requirement. I solved it using the below code :

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);
 }
}
查看更多
在下西门庆
6楼-- · 2019-01-17 12:54

What you are using is a heterogeneous container. These can be made typesafe by using type tokens (as you already do) and Class.cast() with the correct application logic: So there is an unchecked suppressWarning within Class.cast(), but the application logic guarantees correctness.

I advise you read Josh Bloch's Effective Java Item 29: Consider typesafe heterogeneous containers. His example is:

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

I only see a possibility for memory leakage if you hold arbitrarily many different types you actually no longer need.

查看更多
登录 后发表回答