2016-11-21 4 views
2

У меня есть класс, который расширяет параметризованную версию HashSet. Этот класс имеет внутреннее поле currentSize, которое отслеживает, сколько элементов было добавлено до сих пор. Класс child переопределяет базовый класс 'add и addAll, поэтому соответственно увеличивается currentSize. Моя проблема заключается в том, что внутри addAll размер набора добавляется два раза к счетчику currentSize, не один раз. Ниже мой класс Код:Метод hashSet addAll изменяет внутреннее поле класса

public class InheritHashSet extends HashSet<Integer> { 
    private int currentSize = 0; 

    @Override 
    public boolean add(Integer e) { 
     currentSize++; 
     super.add(e); 
    } 

    @Override 
    public boolean addAll(Collection<? extends Integer> e) { 
     currentSize += e.size(); 
     super.addAll(e); 
    } 

    public int getCurrentSize() { 
     return currentSize; 
    } 
} 

Метод add, кажется, работает нормально, так как после добавления трех элементов, currentSize является 3, но следующий будет добавить 6 к currentSize вместо 3:

InheritHashSet ihs = new InheritHashSet(); 
Collection<Integer> c = new LinkedList<Integer>(); 
c.add(new Integer(0)); 
c.add(new Integer(1)); 
c.add(new Integer(2)); 
ihs.addAll(c); 
System.out.println(ihs.getCurrentSize()); // prints 6 instead of 3 

Похоже, что вызов super.addAll(e) также изменяет currentSize (это, похоже, не имеет никакого смысла).

+1

Что 'super.addAll (е), 'делать? –

+3

Именно поэтому вы не должны распространять HashSet, но вместо этого используйте * HashSet. Обратите внимание, что currentSize очень плохо назван. Это совсем не размер. И если бы это было так, это было бы бесполезно, поскольку у HashSet уже есть размер. –

+0

@JBNizet Я знаю, что размер можно определить с помощью метода 'size()' HashSet, мне просто интересно, почему этот метод подсчета числа элементов в наборе не дает правильного ответа. – Polb

ответ

2

Метод addAll()InheritHashSet класс первый комплект currentSize = 3, с currentSize += e.size(); инструкция. Затем super.addAll(e); звонки add(e) способ три раза. Для динамического связывания public boolean add(Integer e) класса InheritHashSet вызывается первым, а затем currentSize затем увеличивается до 6.

по этой причине вы должны реализовать addAll метод таким образом:

@Override 
public boolean addAll(Collection<? extends Integer> e) { 
    return super.addAll(e); 
} 
+5

Пока HashSet не решит реализовать addAll(), не вызвав add() больше, но делегируя новый частный метод doAdd(), который затем сломает подкласс и приведет к 0 вместо 3 Вы должны просто не расширять HashSet. –

+0

Я полностью согласен, вы правы, чтобы указать на это, но мы не знаем, что на самом деле представляет собой код OP. Может быть, он написал этот код только для простого теста или для изучения.Он спросил только, почему было такое странное поведение, что это было не так незамедлительно. – user6904265

+0

Я что-то забываю, или эта реализация бесполезна? Это просто вызов метода 'super', и не меняя видимости, так в чем смысл этого? И, конечно же, Дж. Б. Низет прав. Это трудно. «Самый чистый» или «безопасный» вариант, вероятно, будет «MySpecialSet расширяет AbstractSet реализует Set», который реализует свои методы 'size',' iterator' и 'add', используя требуемый Set (' HashSet' в этом случае) и делает подсчет только в 'add'. Но я бы поспорил, что есть ** далекие ** более элегантные решения для того, чего на самом деле хочет желающий ... – Marco13

2

Практически не рекомендуется распространять существующий класс коллекции, особенно когда вы пытаетесь обеспечить соблюдение нового контракта.

Я бы порекомендовал вам перепроектировать ваш класс, чтобы иметь поле HashSet, а не расширять HashSet.

Прочитано Effective Java by Joshua Bloch Пункт 16: Преимущество композиции над наследованием.

+0

@Sotirios да, вы были правы, чтобы изменить это. Я бы удалил эту строку в любом случае –