ClassCastException durante il cast di Iterator HashMap su un tipo concreto
-
06-07-2019 - |
Domanda
Sono molto nuovo su processing.org e Java. Sto cercando di archiviare oggetti in una HashMap e quindi scorrere i valori di HashMap, chiamando i metodi sugli oggetti memorizzati. Per fare ciò, suppongo di dover eseguire il downgrade dell'iteratore al tipo della mia classe, ma ciò genera una ClassCastException (" java.util.HashMap $ ValueIterator non può essere trasmesso a sketch_oct27a $ MyClass "). Il seguente codice semplificato dimostra questo comportamento:
import java.util.*;
void setup() {
HashMap m = new HashMap();
m.put("First", new MyClass());
m.put("Second", new MyClass());
m.put("Third", new MyClass());
Iterator iter = m.values().iterator();
while (iter.hasNext()) {
((MyClass)iter).SaySomething(); // Throws ClassCastException
iter.next();
}
}
class MyClass {
void SaySomething() {
println("Something");
}
}
Come posso chiamare il metodo SaySomething () tramite l'iteratore?
Soluzione
Ecco come si usa un iteratore:
((MyClass)iter.next()).SaySomething();
Meglio ancora, usa Generics in modo da non dover assolutamente lanciare:
HashMap<MyClass> m = new HashMap<MyClass>();
...
Iterator<MyClass> iter = m.values().iterator();
...
iter.next().SaySomething();
Puoi anche saltare completamente l'iteratore (in realtà, questa sintassi lo nasconde, è ancora usato implicitamente):
for(MyClass element : m.values())
{
element.SaySomething();
}
Altri suggerimenti
Il tuo codice attualmente lo fa:
((MyClass)iter).SaySomething();
Questo dice " cast iter
come un'istanza di MyClass
e chiama il suo metodo SaySomething ()
. Ciò non riesce perché la classe effettiva dell'istanza iter
sarà una classe interna che implementa l'interfaccia java.util.Iterator
. Quella classe non sarà una sottoclasse di MyClass.
Quello che devi fare è far sì che l'iteratore fornisca il suo prossimo valore e lanci quel valore; cioè.
((MyClass) (iter.next())).SaySomething();
che puoi semplificare a:
((MyClass) iter.next()).SaySomething();
a causa della precedenza dell'operatore Java.
@Michael sottolinea che se usi i generici puoi sbarazzarti del typecast manifesto. Puoi semplificare ulteriormente utilizzando il "nuovo" nuovo per la sintassi del loop introdotta in Java 5.0:
HashMap<String, MyClass> m = new HashMap<String, MyClass>();
m.put("First", new MyClass());
m.put("Second", new MyClass());
m.put("Third", new MyClass());
for (MyClass mc : m.values()) {
mc.SaySomething();
}
In realtà, il ciclo for è solo zucchero sintattico. Sotto le copertine, l'istanza di Iterator viene creata e utilizzata secondo il tuo codice (con la correzione). Anche il cast di tipo viene eseguito ... a meno che la JIT non riesca a capire che può ottimizzarlo via.
EDIT: se non puoi usare Java 1.5, allora sei bloccato nel farlo alla vecchia maniera. Sembra " processing.org " ha bisogno di mettere insieme i loro atti. La piattaforma Java 1.4.x è davvero obsoleta.