пʼятницю, 17 квітня 2020 р.

Клас HashSet

HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.

Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.

Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.

HashSet має такі конструктори:
HashSet()
HashSet (Collection  c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.

Наступний приклад демонструє роботу із HashSet.
import java.util.HashSet;

public class TestHashSet {

    HashSet<String> hs=new HashSet<String>();
    public static void main(String[] args) {
        TestHashSet test=new TestHashSet();
        test.test();
    }
    void test(){
        hs.add("Австрія");
        hs.add("Україна");
        hs.add("США");
        System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
        hs.add("Австрія"); // помилки не буде, але в HashSet нічого не поміняється
        System.out.println("2) Після спроби додати Австрію ще раз: "+hs);
        hs.remove("США"); //видаляємо США з множини
        hs.add("Німеччина");
        hs.add("Англія");
        hs.add(null);
        hs.add(null); // другий раз не додаситься
        System.out.println("3)"+hs);
        System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
        System.out.println("5) Множина пуста? "+hs.isEmpty());
        //можемо також отримати ітератор, або ж перебрати множину у for earch
        for (String str:hs){
         System.out.println(str);
         }
        hs.clear(); // очистити
        System.out.println("6) Розмір після очищення="+hs.size());
    }
}

Результат виконання:
1) Три країни: [Австрія, Україна, США] розмір=3
2) Після спроби додати Австрію ще раз: [Австрія, Україна, США]
3)[null, Австрія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австрія
Німеччина
Україна
Англія
6) Розмір після очищення=0
Зробити копію хеш множини можна так:
HashSet<String> hsc=(HashSet)hs.clone();
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.

При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.

Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
Set s = Collections.synchronizedSet (new HashSet (...))

У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().

Додатково:
* Working With hashcode() and equals()

Немає коментарів:

Дописати коментар