2013-05-30 14 views
20

Se la chiave di un HashMap è un array di stringhe:Può una matrice java essere usato come un HashMap chiave

HashMap<String[], String> pathMap; 

Potete accedere alla mappa utilizzando un array di stringhe appena creato o ha per essere la stessa stringa [] oggetto?

pathMap = new HashMap<>(new String[] { "korey", "docs" }, "/home/korey/docs"); 
String path = pathMap.get(new String[] { "korey", "docs" }); 
+2

No; gli array non eseguono l'override di 'hashCode()'. – SLaks

+0

Strettamente correlato a una [domanda simile su 'Set's] (http://stackoverflow.com/questions/9841934/how-to-make-a-set-of-array-in-java). – Raedwald

risposta

28

Deve essere lo stesso oggetto. A HashMap confronta le chiavi usando equals() e due array in Java sono uguali solo se sono lo stesso oggetto.

Se si vuole il valore dell'uguaglianza, quindi scrivere la propria classe contenitore che avvolge una String[] e fornisce la semantica appropriate per equals() e hashCode(). In questo caso, sarebbe meglio rendere il contenitore immutabile, poiché la modifica del codice hash per un oggetto riproduce il caos con le classi contenitore basate sull'hash.

EDIT

Come altri hanno fatto notare, List<String> ha la semantica ti sembra di desiderare per un oggetto contenitore. Così si potrebbe fare qualcosa di simile:

HashMap<List<String>, String> pathMap; 

pathMap.put(
    // unmodifiable so key cannot change hash code 
    Collections.unmodifiableList(Arrays.asList("korey", "docs")), 
    "/home/korey/docs" 
); 

// later: 
String dir = pathMap.get(Arrays.asList("korey", "docs")); 
+2

Penso che usi anche 'hashCode()' per determinare l'hash di un oggetto. – pvorb

+1

@pvorb - Infatti. E è improbabile che due array abbiano lo stesso codice hash. Tuttavia, questo non è un requisito per nessuna implementazione Java. In ogni caso, due riferimenti con lo stesso 'hashCode()' vengono quindi confrontati usando 'equals()' per determinare se sono la stessa chiave. –

+0

+1 per ulteriori informazioni. – pvorb

1

array in Java utilizzano Object s' hashCode() e non sostituirla (la stessa cosa con equals() e toString()). Quindi no, tu non puoi non usare gli array come una chiave di hashmap.

+1

Puoi _can_ usarli come chiave, userà qualsiasi cosa l'Object faccia per il suo hashCode ... Non quello che vuole, ma niente ti impedisce di farlo. – Lucas

1

Ted Hopp è giusto che dovrà essere allo stesso oggetto

per informazioni vedere questo esempio

public static void main(String[] args) { 
     HashMap<String[], String> pathMap; 
     pathMap = new HashMap<String[], String>(); 
     String[] data = new String[] { "korey", "docs" }; 
     pathMap.put(data, "/home/korey/docs"); 
     String path = pathMap.get(data); 
     System.out.println(path); 
    } 
} 

Quando si esegue sopra di esso stamperà "docs".

+0

Stampa "/ home/korey/docs" come previsto –

6

No, ma è possibile utilizzare List<String> che funzionerà come previsto!

+7

Questo funziona con un avvertimento. Se si utilizza un 'Elenco ' come chiave in una raccolta basata su hash, l'elenco dovrebbe essere non modificabile. Se il codice hash di un oggetto cambia mentre l'oggetto viene utilizzato come chiave in una raccolta basata su hash, generalmente la raccolta si interrompe. –

+0

'List' è un'interfaccia, e non vi è alcuna garanzia che un'implementazione abbia la precedenza su uguali e hashCode –

+1

@SteveKuo - Sì, c'è. La documentazione di 'List' richiede qualsiasi implementazione per usare una semantica specifica per' equals() 'e' hashCode() '. La semantica richiesta corrisponde a ciò che OP sembra volere. –

1

Non è possibile utilizzare Java Array come chiave in un HashMap. (Bene, ma non funzionerà come previsto.)

Ma si potrebbe scrivere una classe wrapper che ha un riferimento alla matrice e che sovrascrive anche hashCode() e equals().

+0

Non è necessario scrivere una nuova classe wrapper di array, ne esiste già una - 'ArrayList' –

+0

@SteveKuo Sì, infatti. Ma forse vuoi scriverlo da solo, dato che 'ArrayList' è mutabile e l'array sottostante può essere sostituito internamente senza che tu te ne accorga. – pvorb

+1

@pvorb - Si può sempre usare 'Collections.unmodifiableList (someList)' per trasformare un 'Elenco' in un oggetto immutabile. –

0

Nella maggior parte dei casi, quando le stringhe all'interno dell'array non sono patologiche e non includono virgole seguite da uno spazio, è possibile utilizzare Arrays.toString() come chiave univoca. Ad esempio, il tuo Map sarebbe un Map<String, T>. E il get/put per una serie myKeys[] sarebbe

T t = myMap.get(Arrays.toString(myKeys)); 

myMap.put(Arrays.toString(myKeys), myT); 

Ovviamente si poteva mettere in qualche codice wrapper se lo si desidera.

Un piacevole effetto collaterale è che la chiave è ora immutabile. Ovviamente, cambierai i tuoi array myKeys e poi proverai uno get(), non lo troverai.

Hashing of Strings è altamente ottimizzato.Quindi la miaè che questa soluzione, sebbene sia un po 'lenta e pesante, sarà più veloce e più efficiente in termini di memoria (meno allocazioni di oggetti) rispetto alla soluzione @Ted Hopp che utilizza una lista immutabile. Basti pensare se lo Arrays.toString() è unico per le tue chiavi. In caso contrario, o in caso di dubbio, (ad esempio, la stringa [] deriva dall'input dell'utente) utilizzare l'elenco.

Problemi correlati