2012-04-17 14 views
13

No estoy seguro de qué es lo que quiero hacer es posible, pero si lo es, quiero averiguar cómo. Básicamente, quiero crear un mapa donde la clave sea una clase (java.lang.Class), y el valor de esa entrada es una instancia de esa clase. Actualmente tengoMapa de Java, clave = clase, valor = instancia de esa clase

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

Sin embargo, esto significa que cualquier objeto se puede colocar en el mapa. Si es posible, quiero hacerlo, así que solo una instancia de la clase en la clave se puede colocar en el mapa. ¿Hay alguna forma de usar el? la parametrización en la clase para asegurar esto?

Además, encontré que podría haber un possible memory leak al hacer algo como esto. No estoy seguro de entender completamente cómo sucede esto. Solo insertaré objetos únicos en el mapa, así que ¿todavía habría preocupación por una pérdida de memoria? Si es así, ¿cómo lo evito?

+0

Con lo que estoy haciendo, no es crítico que me asegure de esto.Solo quería saber si era posible. Sin embargo, es bueno saber todo esto para referencia futura. – dnc253

Respuesta

10

El sistema de tipos de Java simplemente no es lo suficientemente fuerte como para aplicar la restricción de tipo que está describiendo directamente, y tendrá que hacer moldes inseguros para hacerlo funcionar o ajustar el Map en alguna otra API que refuerce el tipo de seguridad. Guava'sClassToInstanceMap hace exactamente eso para este caso de uso, proporcionando una API segura externamente que impone restricciones adicionales en la interfaz Map para que funcione. (Divulgación: contribuyo a Guava).

La única vez que esto puede causar una pérdida de memoria es si hay algunas clases que está utilizando aquí que no se conservarán durante la vida de la aplicación. Esto no es una preocupación para muchos usuarios, especialmente si está escribiendo una aplicación "del lado del servidor" que no está tan preocupada por la descarga de clases no utilizadas.

+0

Dado esto, tal vez una solución simplista sea extender HashMap y anular el método de poner para hacer cumplir que el valor es de la misma clase que la clave. – elevine

+1

Debo admitir que en general no me gusta esa solución porque todavía tendrás que hacer moldes y todo, y no obtienes los beneficios de la seguridad de tipo en tiempo de compilación. –

+0

+1 para "o ajuste el mapa en alguna otra API que aplique el tipo de seguridad" (y para contribuir a Guava :). Pero ¿no puede hacer esto con un simple Class.cast() (vea mi respuesta a continuación)? – DaveFar

0

Esto no es posible debido al borrado de tipo.

Sin embargo, usted podría subclase HashMap y escribir algo de lógica en el método put que hacer esto para usted:

public void put(K key, V value) { 

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

(Código para propósitos ilustrativos solamente)

6

Puede ocultar la colección y sólo permitir que se acceda a través de métodos de acceso.

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

La advertencia puede ser ignorado como sabe el reparto en el último método es seguro, incluso si el compilador no lo hace.

5

Lo que está utilizando es un heterogeneous container. Estos pueden hacerse tipo seguro mediante el uso de tokens de tipo (como ya lo hace) y Class.cast() con la lógica de aplicación correcta: De modo que hay un supresión de supresión sin control dentro de Class.cast(), pero la lógica de la aplicación garantiza la corrección.

Le aconsejo que lea Josh Bloch's Effective Java, artículo 29: Considere contenedores heterogéneos tipo seguro. Su ejemplo es:

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

solamente veo una posibilidad de fugas de memoria si se mantiene arbitrariamente muchos tipos diferentes que en realidad ya no lo necesitan.

Cuestiones relacionadas