Настройка Java-обобщений итераторов - PullRequest
1 голос
/ 07 ноября 2011

Я заметил нечто забавное, что делает Java (или, по крайней мере, Netbeans), когда я использую классы, реализующие ArrayList и изменяющие тип элементов. Я в основном создал абстрактный класс, который расширяет ArrayList и некоторые подклассы, которые должны работать с String объектами (что-то вроде ArrayList<String>). Одна из вещей, которые я сделал, чтобы попытаться достичь этого, заключалась в следующем:

public abstract class A extends ArrayList {
   ...
}
@Override
public abstract class B extends A {
   public Iterator<String> iterator() {
      return super.iterator();
   }
}

Еще один был такой:

public abstract class A extends ArrayList {
   ...
}
public abstract class B<String> extends A {
   @Override
   public Iterator<String> iterator() {
      return super.iterator();
   }
}

Первый успешно переопределяет метод iterator(), присваивающий ему строковое значение. Другой каким-то образом отменяет приведение типов. Самое смешное, что ни один из них не работает, когда дело доходит до петель. Это получает тип Object вместо String.

for (String s : B) {
   ...
}

У вас есть идея, почему это происходит и как я могу это исправить, не реализовав свой собственный итератор?

Ответы [ 4 ]

4 голосов
/ 07 ноября 2011

Не уверен, что вы пытаетесь сделать, но если я правильно понимаю, вам нужен класс, который расширяет ArrayList и имеет общий тип String ... Возможно, вы ищете это:

public abstract class A<T> extends ArrayList<T> {
    ...
}
public abstract class B extends A<String> {
    ...
}

Тогда в вашем коде это:

B myList = ...;
for ( String s : myList ) {
    ...
} 

Будет работать просто отлично. Хотя я думаю, что вы могли бы придумать гораздо лучшее решение. У вас есть больше подробностей о вашей проблеме?

1 голос
/ 07 ноября 2011

Используйте композицию вместо Наследования

    public class A implements Iterable<String>{
        List<String> myList = new ArrayList<String>();
        //do operations on myList
        public Iterator<String> iterator() {
             return myList.iterator();
        }
    }
0 голосов
/ 08 ноября 2011

О Боже, это ужасно:

public abstract class B<String> extends A {
   @Override
   public Iterator<String> iterator() {
      return super.iterator();
   }
}

String - это не класс String, скорее вы объявляете новую переменную типа с именем String (например, T), которая затеняеткласс String

0 голосов
/ 07 ноября 2011

Если вы расширяете родовой класс, вы должны заботиться о дженериках. Я имею в виду, что ваша декларация должна выглядеть как

public abstract class A extends ArrayList<String> {
   ...
}

, если вы хотите использовать строки или

public abstract class <T> A extends ArrayList<T> {
   ...
}

если вы хотите, чтобы ваш класс был общим.

В обоих случаях вам не нужно переопределять метод iterator(): вы можете вызвать его из суперкласса, и он вернет вам "хороший" итератор. Ваша декларация эквивалентна

public abstract class A extends ArrayList<Object> {
   ...
}

Это причина "странного" поведения.

Кстати, могу я спросить вас, почему вы расширяете ArrayList? Это действительно звучит странно.

...