2012-04-17 13 views
13

Non sono sicuro di cosa voglio fare, ma se lo è, voglio sapere come. Fondamentalmente, voglio creare una mappa in cui la chiave è una classe (java.lang.Class) e il valore per quella voce è un'istanza di quella classe. Attualmente hoJava map, key = class, value = istanza di quella classe

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

Tuttavia, questo significa che qualsiasi oggetto può essere inserito nella mappa. Se è possibile, voglio farlo, quindi solo un'istanza della classe nella chiave può essere inserita nella mappa. C'è un modo per usare il? parametrizzazione sulla classe per garantire questo?

Inoltre, ho trovato ci potrebbe essere un possible memory leak quando si fa qualcosa di simile. Non sono sicuro di comprendere appieno come ciò avvenga. Attaccherò solo oggetti singoli nella mappa, quindi ci sarebbe ancora preoccupazione per una perdita di memoria? Se sì, come posso prevenirlo?

+0

Con quello che sto facendo, non è fondamentale che lo garantisco.Volevo solo sapere se era possibile. È bello sapere tutto questo per riferimento futuro però. – dnc253

risposta

10

Il sistema di tipo Java non è abbastanza potente per applicare il vincolo di tipo che stai descrivendo direttamente, e dovrai eseguire alcuni cast non sicuri per farlo funzionare - o avvolgere lo Map in qualche altra API che impone il digitare sicurezza. Guava'sClassToInstanceMap fa proprio questo esattamente per questo caso d'uso, fornendo un'API esternamente sicura che impone ulteriori restrizioni all'interfaccia Map per farlo funzionare. (Divulgazione: contribuisco a Guava.)

L'unica volta che ciò può causare una perdita di memoria è se ci sono alcune classi che stai usando qui che non verrebbero mantenute per la vita dell'applicazione. Questa non è una preoccupazione per molti utenti, specialmente se si sta scrivendo un'applicazione "lato server" che non è così preoccupata per lo scarico di classi non utilizzate.

+0

Dato questo, forse una soluzione semplicistica è estendere HashMap e sovrascrivere il metodo put per far sì che il valore provenga dalla stessa classe della chiave. – elevine

+1

Devo ammettere che per la maggior parte questa soluzione non mi piace, perché devi ancora fare cast e tutto, e non ottieni i benefici della sicurezza dei tipi in fase di compilazione. –

+0

+1 per "o avvolgere la Mappa in qualche altra API che impone il tipo sicurezza" (e per contribuire a Guava :) Ma non puoi farlo con un semplice Class.cast() (vedi la mia risposta sotto)? – DaveFar

0

Questo non è possibile a causa della cancellazione del tipo.

Tuttavia, si potrebbe creare una sottoclasse HashMap e scrivere una certa logica nel metodo put che farà questo per voi:

public void put(K key, V value) { 

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

(codice solo a scopo illustrativo)

6

È possibile nascondere la raccolta e solo consentirne l'accesso tramite i metodi di accesso.

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

L'avviso può essere ignorato come sapete il cast nell'ultima metodo è sicuro, anche se il compilatore non lo fa.

5

Quello che si utilizza è un heterogeneous container. Questi possono essere convertiti in typesable utilizzando i token di tipo (come già si fa) e Class.cast() con la logica dell'applicazione corretta: esiste quindi un soppressore non controllatoAvviso entro Class.cast(), ma la logica dell'applicazione garantisce la correttezza.

Ti consiglio di leggere Josh Bloch's Effective Java Item 29: consideri i contenitori eterogenei di tipo typesafe. Il suo esempio è:

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

vedo solo una possibilità per perdite memoria se si tiene arbitrariamente molti tipi diversi che in realtà non hanno più bisogno.

Problemi correlati