Как избежать непроверенных приведений в переопределенных методах Collection? - PullRequest
2 голосов
/ 21 октября 2009

Я работаю над реализацией List. Из-за этого мне придется переопределить методы

Collection.containsAll(Collection<?> c);
Collection.removeAll(Collection<?> c);
Collection.retainAll(Collection<?> c);

Но, как объясняет Sun , они принимают коллекции с любым видом контента (обратите внимание на <?>). Таким образом, коллекция не проверяется компилятором, и я должен это проверить. Но как это сделать? instanceof для каждого элемента не будет работать из-за стирания типа. Следующим решением было бы наложить каждый элемент на улов ClassCastException. Смотрите здесь:

public boolean containsAll( Collection<?> c ) {
    boolean foundAll = true;
    for ( Object element : c ) {
        try {
            foundAll &= this.contains( (T) element );
        } catch ( ClassCastException e ) {
            foundAll = false;
        }
    }
    return foundAll;
}

Два других метода выглядят одинаково. Это работает. Но это дает мне предупреждение компилятора "предупреждение: [не проверено] не проверено приведение"! Если я не подавлю это с помощью «@SuppressWarnings("unchecked")», он не будет компилироваться нормально.

Я не хочу полагаться на "@SuppressWarnings("unchecked")", если мне действительно не нужно. Есть ли способ избежать этого? Как бы вы реализовали такие методы, как containsAll(Collection<?> c)?

редактировать

Хорошо, извините, ребята, я не был достаточно ясен. Я не расширяю AbstractList и не хочу. Мой список реализован с помощью сбалансированного двоичного дерева. У меня есть собственная реализация insert(), remove(), contains() (которая фактически выполняет поиск листа) и т. Д., И все они принимают аргумент (универсального) типа T. Основная цель - создать отсортированный список, который можно изменять, пока он повторяется.

Итак ... как мне избежать предупреждения в containsAll(Collection <?>)? Я должен бросить!

Спасибо! craesh

Ответы [ 4 ]

9 голосов
/ 21 октября 2009

Вам не нужно приводить элемент к T при вызове contains(), так как он определен как boolean contains(Object o). Обратите внимание, что вы можете спросить Collection<String>, является ли contains() объект Integer. Нет необходимости в кастинге.

remove() также принимает Object, поэтому не нужно вообще литье.

И, кстати: расширение AbstractList отнимает большую часть скучной работы по реализации List.

2 голосов
/ 21 октября 2009

Просто чтобы прояснить неправильное представление о дженериках:

instanceof для каждого элемента не будет работать из-за стирания типа.

Нет, это не правильно. instanceof будет работать просто отлично. «Стирание типа» просто означает, что вы не можете получить в тип времени компиляции , который был объявлен через дженерики для коллекции, которую вы получаете, - но вам все равно об этом.

То, что вы хотите проверить, это тип времени выполнения элемента, который вы получаете. Это делается через instanceof, полностью не зависит от генериков и будет работать.

Конечно, как указывает Йоахим Зауэр, вам даже не нужно проверять тип в этом конкретном случае, так что в любом случае вопрос спорный ...

Edit:

На самом деле JavaC AbstractCollection делает это так:

public boolean containsAll(Collection<?> c) {
    Iterator<?> e = c.iterator();
    while (e.hasNext())
    if(!contains(e.next()))
        return false;
    return true;
}

(из источников Sun JDK).

Так что вы действительно должны пытаться наследовать от AbstractList или, по крайней мере, AbstractCollections

0 голосов
/ 04 ноября 2009

Если вы не хотите расширять AbstractList, хотя бы расширьте AbstractCollection. Тогда вам вообще не нужно будет реализовывать этот метод, и вопрос будет спорным.

0 голосов
/ 21 октября 2009

конечно, вы можете расширить AbstractList, чтобы получить эти методы бесплатно, но вы также можете выполнить итерацию this вместо c:

@Override
public boolean containsAll(Collection<?> c) {
    Iterator<T> it = this.iterator();

    while (it.hasNext()) {
        if (!c.contains(it.next())) {
            return false;
        }
    }

    return true;
}

или просто:

@Override
public boolean containsAll(Collection<?> c) {
    for (Object o : this) {
        if (!c.contains(o)) {
            return false;
        }
    }

    return true;
}
...