Почему Карта Java не расширяет Набор?

Я был удивлен фактом это Map не a Collection.

Я думал, что это имело бы БОЛЬШОЙ смысл, если бы это было объявлено как таковое:

public interface Map extends Collection>

В конце концов, a Map набор Map.Entry,не так ли?

Так существует ли серьезное основание, почему оно не реализовало как таковой?


Благодаря Cletus для самого авторитетного ответа, но я все еще задаюсь вопросом, почему, если можно уже просмотреть a Map как Set> (через entrySet()), это только расширяет тот интерфейс вместо этого.

Если a Map a Collection, каковы элементы? Единственным разумным ответом являются "Пары"ключ-значение""

Точно, interface Map extends Set> было бы большим!

но это обеспечивает очень ограниченный (и не особенно полезное) Map абстракция.

Но если это так затем, почему entrySet указанный интерфейсом? Это должно быть полезно так или иначе (и я думаю, что легко привести доводы в пользу того положения!).

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

Я не говорю это вот и все Map! Это может и должно сохранить все другие методы (кроме entrySet, который избыточен теперь)!

142
задан toniedzwiedz 4 July 2019 в 14:06
поделиться

6 ответов

Из FAQ по проектированию API коллекций Java :

Почему карта не расширяет коллекцию?

Это было сделано намеренно. Мы считаем, что отображения не являются коллекциями, а коллекции не являются отображениями. Таким образом, Map не имеет смысла расширять интерфейс Collection (или наоборот ).

Если Карта является Коллекцией, каковы элементы ? Единственный разумный ответ - "пары ключ-значение", но этот предоставляет очень ограниченную (и не особенно полезную) абстракцию карты. Вы можете ' • спрашивать, какому значению сопоставляется данный ключ , и вы не можете удалить запись для данного ключа, не зная, какому значению он сопоставляется.

Можно создать коллекцию для расширения карты , но возникает вопрос: каковы ключи? На самом деле удовлетворительного ответа нет, а принуждение к нему приводит к неестественному интерфейсу.

Карты можно рассматривать как Коллекции (из ключей, значений или пар), и этот факт отражается в трех «Операциях просмотра Коллекции » на Картах ( keySet, entrySet и значения). Хотя, по принципу , список можно рассматривать как отображение индексов карты на элементы, у него есть неприятное свойство, которое удаляет элемент из Список изменяет ключ, связанный с каждым элементом перед удаленным элементом. Вот почему у нас нет операции просмотра карты для списков.

Обновление: Думаю, цитата отвечает на большинство вопросов. Стоит подчеркнуть, что набор записей не является особенно полезной абстракцией. Например:

Set<Map.Entry<String,String>>

разрешит:

set.add(entry("hello", "world"));
set.add(entry("hello", "world 2");

(при условии, что метод entry () создает карту .Entry instance)

Map s требуют уникальных ключей, так что это нарушит это. Или, если вы вводите уникальные ключи в Set записей, это не совсем Set в общем смысле. Это набор с дополнительными ограничениями.

Можно предположить, что отношение equals () / hashCode () для Map.Entry связано исключительно с ключом, но даже с этим есть проблемы. Что еще более важно, действительно ли это добавляет ценности? Вы можете обнаружить, что эта абстракция не работает, как только вы начнете рассматривать угловые случаи.

Стоит отметить, что HashSet фактически реализован как HashMap , а не наоборот. Это чисто деталь реализации, но, тем не менее, интересная.

Основная причина существования entrySet () состоит в том, чтобы упростить обход, чтобы вам не приходилось обходить ключи, а затем выполнять поиск ключа. Не воспринимайте это как очевидное доказательство того, что Карта должна быть Набором записей (imho).

121
ответ дан 23 November 2019 в 23:06
поделиться

Точно, interface Map extends Set > было бы здорово!

На самом деле, если бы реализует Map , Set > , то я склонен согласиться .. Это кажется даже естественным. Но это не очень хорошо работает, правда? Допустим, у нас есть HashMap реализует Map , Set , LinkedHashMap реализует Map , Set и т.д ... это все хорошо, но если у вас есть entrySet () , никто не забудет реализовать этот метод, и вы можете быть уверены, что можете получить entrySet для любой карты, тогда как вы этого не делаете, если надеетесь, что разработчик реализовал оба интерфейса ...

Причина, по которой я не хочу иметь интерфейс Map расширяет Set > - это просто, потому что методов будет больше. А ведь это разные вещи, правда? Также очень практично, если я попаду на карту . в IDE, я не хочу видеть .remove (Object obj) и .remove (запись Map.Entry ) , потому что я могу ' t do нажмите ctrl + пробел, r, верните и покончите с этим.

0
ответ дан 23 November 2019 в 23:06
поделиться

Думаю, почему субъективно.

В C #, я думаю, Dictionary расширяет или, по крайней мере, реализует коллекцию:

public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, 
    ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, 
    IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback

В Pharo Smalltak также:

Collection subclass: #Set
Set subclass: #Dictionary

Но есть асимметрия с некоторыми методами. Например, collect: принимает ассоциацию (эквивалент записи), а do: принимает значения. Они предоставляют другой метод keysAndValuesDo: для перебора словаря по записи. Добавить: принимает ассоциацию, но remove: был «подавлен»:

remove: anObject
self shouldNotImplement 

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

Что лучше, то субъективно.

10
ответ дан 23 November 2019 в 23:06
поделиться

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

Проблема здесь в том, что наследование моделирует только один тип общности. Если вы выберете две вещи, которые кажутся «коллекционными», вы, вероятно, сможете выделить 8 или 10 вещей, которые у них общего. Если вы выберете другую пару «похожих на коллекцию» вещей, у них также будет 8 или 10 общих вещей, но это не будут те же 8 или 10 вещей, как первая пара.

Если вы посмотрите на дюжину или около того разных «коллекционных» вещей, практически каждая из них, вероятно, будет иметь что-то вроде 8 или 10 общих характеристик хотя бы с одной другой - но если вы посмотрите на то, что разделяют через каждый один из них у вас практически ничего не остается.

Это ситуация, когда наследование (особенно одиночное наследование) просто плохо моделируется.Нет четкой границы между тем, какие из них на самом деле являются коллекциями, а какие нет, но если вы хотите определить значимый класс Collection, вы застряли, оставив некоторые из них. Если вы оставите только несколько из них, ваш класс Collection сможет предоставить только довольно разреженный интерфейс. Если вы оставите больше, вы сможете сделать интерфейс более богатым.

Некоторые также используют вариант, в основном говоря: «этот тип коллекции поддерживает операцию X, но вам не разрешено ее использовать, производя от базового класса, определяющего X, но пытаясь использовать производный класс 'X терпит неудачу (например, выбрасывая исключение).

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

10
ответ дан 23 November 2019 в 23:06
поделиться

Ответ Клетуса хороший, но я хочу добавить семантический подход. Объединять оба варианта не имеет смысла, представьте себе случай, когда вы добавляете пару ключ-значение через интерфейс коллекции, а ключ уже существует. Интерфейс карты допускает только одно значение, связанное с ключом. Но если вы автоматически удалите существующую запись с тем же ключом, коллекция после добавления будет иметь тот же размер, что и раньше, что очень неожиданно для коллекции.

3
ответ дан 23 November 2019 в 23:06
поделиться

Коллекции Java не работают. Отсутствует интерфейс Relation. Следовательно, Map extends Relation extends Set. Отношения (также называемые мульти-картами) имеют уникальные пары имя-значение. Карты (также известные как «Функции») имеют уникальные имена (или ключи), которые, конечно, сопоставляются со значениями. Последовательности расширяют Карты (где каждый ключ является целым числом> 0). Пакеты (или мульти-наборы) расширяют Карты (где каждый ключ является элементом, а каждое значение - это количество раз, которое элемент появляется в сумке).

Эта структура допускает пересечение, объединение и т. Д. Ряда «коллекций». Следовательно, иерархия должна быть такой:

                                Set

                                 |

                              Relation

                                 |

                                Map

                                / \

                             Bag Sequence

Sun / Oracle / Java ppl - пожалуйста, сделайте это правильно в следующий раз. Спасибо.

2
ответ дан 23 November 2019 в 23:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: