Try English version of Quizful



Раздаем бесплатные Q! подробности в группе Quizful.Alpha-test
Партнеры
Рекрутерам: Прескрининг кандидатов about
Топ контрибуторов
loading
loading
Знаете ли Вы, что

Свои вопросы для тестов можно добавлять на странице с информацией о тесте. При этом для некоторых тестов добавление вопросов закрыто

Лента обновлений
ссылка 20:57:36
Комментарий от Recrut_rf:
Спасибо, сохранил функцию, может пригодится когда - ни...
ссылка 20:53:59
Добавлен вопрос в тест ASP.NET - Основы
ссылка 08:41:09
Комментарий от Krosster:
Гарний сайт для новачків. Правда деякі питання підступн...
ссылка Apr 22 22:06
Добавлен вопрос в тест SQL - Средний уровень
ссылка Apr 22 10:13
Комментарий от Entrery:
вроде выбрал ООП в сишарпе, а тут вопросы по джаве...
Статистика

Тестов: 153, вопросов: 8596. Пройдено: 402470 / 1961091.

Миф об уникальности объектов в Set и ключей в Map

head tail Статья
категория
Java
дата27.06.2010
авторStan
голосов12
1. A Set is a Collection that cannot contain duplicate elements  [1]

2. A Map is an object that maps keys to values. A map cannot contain duplicate keys: Each key can map to at most one value. [2]

С этих слов начинаются учебные пособия по соответствующим интерфейсам фреймворка Collections, входящего в стандартный набор утилит языка Java. Трудно с этим не согласиться, когда об этом пишет такой надежный источник, да и все вокруг цитируют данный факт. Однако не стоит забывать об кривых руках, плохом дизайне и прочих непотребствах, которые имею место в современном мире разработки программного обеспечения.

Натолкнувшись на интересный вопрос, задаваемый на собеседованиях [3], мне стало интересно проверить, а что же действительно случится, если объект, исполняющий функции ключа в Map изменить? И как поведёт себя данный экземпляр при попытке уровнять несколько ключей?

Известно, что уникальность ключей Map проверяется равенством объектов по методу equals (obj1.equals(obj2) == true), а также хеш-коды данных объектов также должны быть идентичными (obj1.hashCode() == obj2.hashCode()). Исходя из этого, не трудно представить, что необходимо сделать, чтобы поместить в Map пару тройку одинаковых ключей для различных значений. Что я и сделал:

package test;


import java.util.HashMap;
import java.util.Map;
/**
 * Класс, опровергающий факт о том, что реализациии интерфейса Map
 * не могут содержать неуникальные объекты ключей.
 * Также демонстрирует Set, стандартная реализация которого содержит
 * неуникальные объекты.
 */
public class Myth {
   
    private String dataMember;
   
    public void setDataMember(String dataMember) {
        this.dataMember = dataMember;
    }

    public Myth(String dataMember) {
        this.dataMember = dataMember;
    }

    // любезно сгенерированный Eclipse
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((dataMember == null) ? 0 : dataMember.hashCode());
        return result;
    }

    // любезно сгенерированный Eclipse
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        Myth other = (Myth) obj;
        if (dataMember == null) {
            if (other.dataMember != null) return false;
        } else if (!dataMember.equals(other.dataMember))
            return false;
        return true;
    }

    /**
     * Метод печатает в стандартный поток вывода информацию
     * о равенстве передаваемых объектов.
     */
    static void comparePrint(final Object obj1, final Object obj2) {
        System.out.println("Comparing by \"equals\"   is " + obj1.equals(obj2));
        System.out.println("Comparing by \"hashCode\" is " + (obj1.hashCode() == obj2.hashCode()));
    }

    /**
     * Метод печатает в стандартный поток вывода информацию
     * о количестве объектов, содержащихся в Map.
     */
    static void mapSizePrint(final Map map) {
        System.out.println("Map size is " + map.size());
    }

    public static void main(String[] args) {
        // создание объектов ключей
        final Myth key1 = new Myth("hoho");
        final Myth key2 = new Myth("haha");

        // печатаем в консоли данные о сравнении объектов
        comparePrint(key1, key2);    // Comparing by "equals"      is false
                                                    // Comparing by "hashCode" is false
       
        // создание объекта Map, содержащего объекты с очень
        // важной информацией ;)
        final Map<Myth,Object> map = new HashMap<Myth,Object>();
        map.put(key1, "Very important data 1");
        map.put(key2, "Very important data 2");
       
        mapSizePrint(map);    // Map size is 2

        // по велению кривых рук или плохого дизайна программы
        // изменяем объект второго ключа на идентичный первому
        key2.setDataMember("hoho");

        // как видно из напечатанного два объекта логически идентичны
        comparePrint(key1, key2);    // Comparing by "equals"      is true
                                                   // Comparing by "hashCode" is true

        // при этом размерность экземпляра Map не поменялась:
        mapSizePrint(map);    // Map size is 2

        // проверяем Set на содержание неуникальных объектов
        int i = 0;
        for (final Myth key : map.keySet()) {
            // как видно Set содержит 2 абсолютно идентичных объекта
            System.out.println("The " + ++i + " key object is " + key);
        }
        // The 1 key object is test.Myth@30f46d
        // The 2 key object is test.Myth@30f46d

        // пытаемся получить значение по первому ключу
        System.out.println(map.get(key1)); // Very important data 1
       
        // пытаемся получить значение по второму ключу
        System.out.println(map.get(key2)); // Very important data 1
    }
}

Как видно "Very important data 2" более не доступна при попытки получить её привычным способом.
Отсюда напрашивается вывод: Как ключи реализаций Map, так и объекты реализаций Set могут содержать одинаковые объекты. Что собственно и требовалось доказать. Ясно было одно, что после инициализации вышеуказанные объекты больше не делают проверок на уникальность, если конечно они не редактируются. Но в любом случае уже имеющиеся объекты остаются на своих местах.

Как писалось выше, данная статья не призвана быть чем-то вроде камнем преткновения при использовании описанных интерфейсов и их реализаций. Скорее показать как несовершенен мир и API документация, если подходить к её прочтению без практического представления о том, как же в действительности реализованы те или иные возможности языка JAVA.

Источники:

[1] - The Set Interface (The Java™ Tutorials > Collections > Interfaces)

[2] - The Map Interface (The Java™ Tutorials > Collections > Interfaces)

[3] - Interview Questions

Если Вам понравилась статья, проголосуйте за нее

Голосов: 12  loading...
art   bu_ma_ga   fiveknight   dimez85   KateAlex   Netscape   Shved90   andrey_z91h   Akoemov   bendor   SamTan   methodBoy