ClassCastException при приведении итератора HashMap к конкретному типу

StackOverflow https://stackoverflow.com/questions/1627784

Вопрос

Я очень новичок в 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 действительно устарела.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top