ClassCastException при приведении итератора HashMap к конкретному типу
-
06-07-2019 - |
Вопрос
Я очень новичок в processing.org и Java. Я пытаюсь сохранить объекты в HashMap, а затем перебрать значения HashMap, вызывая методы для хранимых объектов. Для этого я предполагаю, что мне нужно уменьшить итератор до типа моего класса, но это вызывает исключение ClassCastException (" java.util.HashMap $ ValueIterator не может быть приведен к sketch_oct27a $ MyClass "). Следующий упрощенный код демонстрирует это поведение:
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");
}
}
Как мне вызвать метод SaySomething () через итератор?
Решение
Вот как вы используете итератор:
((MyClass)iter.next()).SaySomething();
Еще лучше, используйте Generics, чтобы вам вообще не приходилось кастовать:
HashMap<MyClass> m = new HashMap<MyClass>();
...
Iterator<MyClass> iter = m.values().iterator();
...
iter.next().SaySomething();
Затем можно даже полностью пропустить итератор (фактически этот синтаксис просто скрывает его, он все еще используется неявно):
for(MyClass element : m.values())
{
element.SaySomething();
}
Другие советы
Ваш код в настоящее время делает это:
((MyClass)iter).SaySomething();
Здесь написано " приведите iter
в качестве экземпляра MyClass
и вызовите его метод SaySomething ()
. Это терпит неудачу, потому что фактический класс экземпляра iter
будет некоторым внутренним классом, который реализует интерфейс java.util.Iterator
. Этот класс не будет подклассом MyClass.
Что вам нужно сделать, это заставить итератор доставить его следующее значение и привести это значение; то есть. р>
((MyClass) (iter.next())).SaySomething();
который вы можете упростить до:
((MyClass) iter.next()).SaySomething();
из-за приоритета оператора Java.
@Майкл указывает, что если вы используете дженерики, вы можете избавиться от явного типа трансляции. Вы можете упростить еще больше, используя " новый " для синтаксиса цикла, введенного в 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();
}
На самом деле цикл for - это просто синтаксический сахар. Под прикрытием создается экземпляр Iterator, который используется в соответствии с вашим кодом (с исправлением). Даже приведение типа выполняется ... если JIT не может выяснить, что он может оптимизировать его.
РЕДАКТИРОВАТЬ: если вы не можете использовать Java 1.5, то вы застряли с этим по старинке. Похоже на «processing.org» нужно собрать их акт. Платформа Java 1.4.x действительно устарела.