2014-11-18 15 views
7

Ciao Mi chiedo se sia possibile accedere direttamente ai contenuti di un HashSet se hai l'Hashcode per l'oggetto che stai cercando, una specie di come usare HashCode come chiave in una HashMap.Accedere a un HashSet utilizzando direttamente HashCode? (Java)

immagino che potrebbe funzionare qualcosa di un po 'come questo:

MyObject object1 = new MyObject(1); 

Set<MyObject> MyHashSet = new HashSet<MyObject>(); 

MyHashSet.add(object1) 

int hash = object1.getHashCode 

MyObject object2 = MyHashSet[hash]??? 

Grazie!

modifica: Grazie per le risposte. Ok, capisco che potrei spingere un po 'il contratto di HashSet, ma per questo particolare progetto l'uguaglianza è determinata esclusivamente dall'hashcode e so per certo che ci sarà un solo oggetto per hashcode/hashbucket. La ragione per cui ero piuttosto riluttante a usare una HashMap è perché avrei bisogno di convertire gli oggetti primitivi con cui sto mappando gli oggetti Integer come HashMap prende solo oggetti come chiavi, e sono anche preoccupato che questo possa influenzare le prestazioni. C'è qualcos'altro che potrei fare per implementare qualcosa di simile?

+0

No, non è possibile. Perché vorresti farlo? Sembra che tu voglia una mappa. –

+2

Nessuna API pubblica di questo tipo. E anche se ci fosse, potrebbe restituire oggetti multipli come i codici hash collidono. – Thilo

+0

Non è possibile ottenere l'oggetto in questo modo. Ha senso poiché due oggetti diversi possono avere lo stesso codice hash ma potrebbero non essere uguali. Hashset confronta internamente due oggetti con il metodo equals se il loro hashcode corrisponde. – BatScream

risposta

2

L'implementazione comune di HashSet è supportata (piuttosto pigramente) da un HashMap così il tuo sforzo per evitare HashMap è probabilmente sconfitto.

Sulla base del fatto che l'ottimizzazione prematura è la radice di ogni male, vi suggerisco di utilizzare un HashMap inizialmente e se il boxing/unboxing sovraccarico di int da e per Integer è davvero un problema dovrete implementare (o trovare) a mano HashSet utilizzando il primitivo int s per il confronto. La libreria Java standard non vuole davvero preoccuparsi dei costi di boxe/unboxing. L'intero linguaggio ha venduto quel problema di prestazioni per un notevole guadagno in semplicità molto tempo fa. Si noti che in questi giorni (dal 2004!) La lingua si apre automaticamente e apre una casella che rivela una politica "non è necessario preoccuparsi di questo". Nella maggior parte dei casi è giusto.

Non so quanto sia "ricco" il tuo HashKeyedSet, ma un hash-table di base non è davvero troppo difficile.

0

Questo non è possibile poiché HashSet è un oggetto e non ci sono API pubbliche come tali. Inoltre, più oggetti possono avere lo stesso codice hash ma gli oggetti possono essere diversi.

Infine è possibile accedere solo agli array utilizzando la sintassi myArray[<index>].

2

HashSet è internamente supportato da un HashMap, che purtroppo non è disponibile tramite l'API pubblica per questa domanda. Tuttavia, siamo in grado di utilizzare la reflection per ottenere l'accesso alla mappa interna e poi trovare una chiave con un identico hashCode:

private static <E> E getFromHashCode(final int hashcode, HashSet<E> set) throws Exception { 
    // reflection stuff 
    Field field = set.getClass().getDeclaredField("map"); 
    field.setAccessible(true); 

    // get the internal map 
    @SuppressWarnings("unchecked") 
    Map<E, Object> interalMap = (Map<E, Object>) (field.get(set)); 

    // attempt to find a key with an identical hashcode 
    for (E elem : interalMap.keySet()) { 
     if (elem.hashCode() == hashcode) return elem; 
    } 
    return null; 
} 

Utilizzato in un esempio:

HashSet<String> set = new HashSet<>(); 
set.add("foo"); set.add("bar"); set.add("qux"); 

int hashcode = "qux".hashCode(); 

System.out.println(getFromHashCode(hashcode, set)); 

uscita:

qux 
+0

Grazie! Questo è un modo brillante per farlo, tuttavia richiede la ricerca attraverso HashSet con un ciclo for, so che ciò che sto chiedendo è impossibile ora ma ho solo pensato che ci fosse un modo per ottenere direttamente i dati in quel codice hash, come se fosse una lista o qualcosa del genere – Kode47

+0

Sospetto che sia possibile farlo in tempo costante con un numero ancora maggiore di hackery, poiché 'HashMap' non ti consente di ottenere il bucket in un indice specifico nella tabella tramite l'API pubblica. – August

0

È possibile scrivere facilmente codice che accederà direttamente alle strutture di dati interne dell'implementazione di HashSet utilizzando la reflection. Naturalmente, il tuo codice dipenderà dai dettagli di implementazione della particolare JVM che stai codificando. Sarai inoltre soggetto ai vincoli del SecurityManager (se presente).

Un'implementazione tipica di HashSet utilizza una HashMap come struttura dati interna. HashMap ha una matrice, che è indicizzata dal codice hash della chiave mappato su un indice dell'array. La funzione di mappatura hash è disponibile chiamando metodi non pubblici nell'implementazione: dovrai leggere il codice sorgente e scoprirlo. Una volta raggiunto il bucket corretto, sarà sufficiente trovare (utilizzando equals) la voce corretta nel bucket.