2014-04-08 27 views
6

Vorrei creare un HashMap che associa tipi di classi specifici a un singolo nuovo oggetto specifico.Come creare una HashMap typesafe generica per tipo di classe?

Successivamente voglio passare il tipo di classe e ottenere il riferimento a quell'oggetto specifico. Esempio semplice:

Map<Class<?>, ?> values = new HashMap<>(); 

public <T> t get(Class<T> type) { 
    return values.get(type); 
} 


//pet and car do not share any interface or parent class 
class Pet; 
class Car; 

//error: not applicable for arguments 
values.put(Pet.class, new Pet()); 
values.put(Car.class, new Car()); 

utilizzo:

values.get(Pet.class); 

Come posso creare tale funzione hashmap e ricerca generica di conseguenza?

+2

Sei alla ricerca di Guava di [ 'ClassToInstanceMap'] (https://code.google.com/p/guava -libraries/wiki/NewCollectionTypesExplained # ClassToInstanceMap)? –

+0

Grande, probabilmente questo è quello che sto cercando di reinventare;) – membersound

risposta

5

è necessario memorizzare alcuni tipo di oggetto, se vuoi essere in grado di mettere qualcos'altro come Object sulla mappa, quindi iniziare con questo:

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

Questo deve essere fatto in questo modo, perché ? non è un oggetto concreto, ma Object è, per il tipo memorizzato nella mappa.

Così il seguente frammento funziona, senza avvisi:

Map<Class<?>, Object> values = new HashMap<>(); 
values.put(Pet.class, new Pet()); 
values.put(Car.class, new Car()); 

Ora il trucco è quello di ottenere gli oggetti, lo facciamo nel modo seguente:

@SuppressWarnings("unchecked") 
private <T> T get(Class<T> clazz) { 
    return (T)values.get(clazz); 
} 

Ora vostro obiettivo è di garantire che la mappa contiene coppie che non forniscono errori in fase di esecuzione. Se inserisci un'istanza new Car() con Car.class, otterrai degli errori.

Così il seguente codice di esempio:

values = new HashMap<>(); 
    values.put(Pet.class, new Pet()); 
    values.put(Car.class, new Car()); 

    System.out.println("get(Pet.class).getClass() = " + get(Pet.class).getClass()); 
    System.out.println("get(Car.class).getClass() = " + get(Car.class).getClass()); 

stamperà:

get(Pet.class).getClass() = class testproject8.Pet 
get(Car.class).getClass() = class testproject8.Car 
1

È possibile utilizzare Object come il tipo di valore:

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

Non conoscere il tipo dei valori in ogni caso.

Quindi, se si vuole essere sicuri che l'oggetto inserito tramite put è della classe che funge da chiave, è possibile creare safePut() seguente modo:

public <T> T safePut(Class<T> key, T value) { 
    return (T) values.put(key, value); 
} 
2

penso che tu sia dopo un contenitore eterogeneo . Non esiste un modo semplice per creare un contenitore di questo tipo in Java senza alcun cast esplicito.

Penso che il modo più semplice è quello di mettere la vostra mappa in una classe -

public class Container { 
    private Map<Class<?>, Object> values = new HashMap<>(); 

    public <T> T put(Class<T> klass, T obj) { 
     return klass.cast(values.put(klass, obj)); 
    } 

    public <T> T get(Class<T> klass) { 
     return klass.cast(values.get(klass)); 
    } 
} 

E utilizzare la classe come segue -

Container c = new Container(); 
c.put(Pet.class, new Pet()); 
c.put(Car.class, new Car()); 
Pet p = c.get(Pet.class); 
Problemi correlati