Я был удивлен тем, что Map<?,?>
не является Collection<?>
.
Я думал, что было бы много смысла, если бы это было объявлено так:
public interface Map<K,V> extends Collection<Map.Entry<K,V>>
В конце концов, это Map<K,V>
коллекция Map.Entry<K,V>
, не так ли?
Так есть ли веская причина, почему это не реализовано как таковое?
Спасибо Cletus за самый авторитетный ответ, но мне все еще интересно, почему, если вы уже можете просматривать Map<K,V>
как Set<Map.Entries<K,V>>
(через entrySet()
), он не просто расширяет этот интерфейс.
Если a
Map
является aCollection
, каковы элементы? Единственный разумный ответ - «Пары ключ-значение»
Точно, interface Map<K,V> extends Set<Map.Entry<K,V>>
было бы здорово!
но это обеспечивает очень ограниченную (и не особо полезную)
Map
абстракцию.
Но если это так, то почему entrySet
указывается интерфейс? Это должно быть как-то полезно (и я думаю, что легко отстаивать эту позицию!).
Вы не можете спросить, к какому значению относится данный ключ, и не можете удалить запись для данного ключа, не зная, к какому значению он соответствует.
Я не говорю, что это все, что нужно сделать Map
! Он может и должен сохранять все другие методы (кроме entrySet
, который сейчас избыточен)!
источник
Ответы:
Из FAQ по разработке API коллекций Java :
Обновление: я думаю, что цитата отвечает на большинство вопросов. Стоит подчеркнуть, что коллекция записей не является особенно полезной абстракцией. Например:
разрешит:
(предполагая
entry()
метод, который создаетMap.Entry
экземпляр)Map
Требуются уникальные ключи, так что это нарушит это. Или, если вы наложите уникальные ключи наSet
записи, это не совсемSet
в общем смысле. ЭтоSet
с дополнительными ограничениями.Можно сказать, что отношение
equals()
/ было чисто ключевым, но даже в этом есть проблемы. Что еще более важно, действительно ли это добавляет ценность? Вы можете обнаружить, что эта абстракция рушится, когда вы начинаете смотреть на угловые случаи.hashCode()
Map.Entry
Стоит отметить, что на
HashSet
самом деле реализован как, аHashMap
не наоборот. Это чисто деталь реализации, но, тем не менее, интересно.Основная причина
entrySet()
существования - это упрощение обхода, чтобы вам не приходилось обходить ключи, а затем выполнять поиск ключа. Не принимайте это как доказательство prima facie, что aMap
должно бытьSet
из записей (imho).источник
entrySet()
действительно, поддерживаетremove
, хотя и не поддерживаетadd
(вероятно, выдаетUnsupportedException
). Итак, я понимаю вашу точку зрения, но опять же, я также вижу точку зрения ОП .. (Мое собственное мнение соответствует изложенному в моем собственном ответе ..)add
могут быть обработаны так же, как этоentrySet()
делает вид: разрешить одни операции и не разрешить другие. Естественным ответом, конечно же, является «Какого родаSet
не поддерживаетadd
?» - хорошо, если такое поведение приемлемоentrySet()
, то почему оно не приемлемо дляthis
? То есть , я имею в основном убежден уже о том, почему это не такая большая идея , как я когда - то мысли, но я до сих пор считаю , что это достойно дальнейшего обсуждения, если только обогатить свое собственное понимание того , что делает дизайн хороший API / ООП.Collection
расширенииMap
?Несмотря на то, что вы получили несколько ответов, которые достаточно прямо касаются вашего вопроса, я думаю, что было бы полезно немного отступить назад и взглянуть на вопрос более широко. То есть не смотреть конкретно на то, как написана библиотека Java, и смотреть, почему она написана именно так.
Проблема здесь в том, что наследование моделирует только один тип общности. Если вы выберете две вещи, которые кажутся «похожими на коллекцию», вы можете выбрать 8 или 10 общих для них вещей. Если вы выберете другую пару «коллекционных» вещей, у них также будет 8 или 10 общих черт, но они не будут такими же, как в первой паре.
Если вы посмотрите на дюжины различных «коллекции, как» вещи, практически каждый из них, вероятно , что - то вроде 8 или 10 общих характеристик, по меньшей мере , один другой , - но если вы посмотрите на то , что общими для каждого одного из них у вас осталось практически ничего.
Это ситуация, когда наследование (особенно одиночное наследование) просто не очень хорошо моделируется. Нет четкой грани между тем, какие из них действительно являются коллекциями, а какие нет, но если вы хотите определить значимый класс Collection, вы застряли на том, чтобы пропустить некоторые из них. Если вы пропустите только несколько из них, ваш класс Collection сможет обеспечить лишь довольно разреженный интерфейс. Если вы оставите больше, вы сможете сделать его более насыщенным.
Некоторые также используют вариант, в основном говоря: «этот тип коллекции поддерживает операцию X, но вы не можете использовать ее, наследуя от базового класса, который определяет X, но пытаясь использовать производный класс« X, не удается (например, , бросив исключение).
Это по-прежнему оставляет одну проблему: почти независимо от того, что вы пропускаете и что вставляете, вам придется провести жесткую грань между тем, какие классы входят, а какие нет. Неважно, где вы проведете эту черту, вы будете иметь четкое, довольно искусственное разделение между некоторыми вещами, которые очень похожи.
источник
Я думаю, почему это субъективно.
Я думаю, что в C #
Dictionary
расширяет или, по крайней мере, реализует коллекцию:В Pharo Smalltak также:
Но есть асимметрия с некоторыми методами. Например,
collect:
will принимает ассоциацию (эквивалент записи), аdo:
принимает значения. Они предоставляют другой методkeysAndValuesDo:
для перебора словаря по записи.Add:
принимает ассоциацию, ноremove:
был «подавлен»:Так что это окончательно выполнимо, но приводит к некоторым другим проблемам, касающимся иерархии классов.
Что лучше, так это субъективно.
источник
Ответ Cletus хорош, но я хочу добавить семантический подход. Объединять оба не имеет смысла, подумайте о случае, когда вы добавляете пару ключ-значение через интерфейс коллекции, и ключ уже существует. Map-интерфейс допускает только одно значение, связанное с ключом. Но если вы автоматически удалите существующую запись с тем же ключом, то после добавления коллекция будет иметь тот же размер, что и раньше - что очень неожиданно для коллекции.
источник
Set
работает, иSet
это осуществитьCollection
.Коллекции Java не работают. Отсутствует интерфейс Relation. Следовательно, карта расширяет отношение расширяет набор. Отношения (также называемые мульти-картами) имеют уникальные пары имя-значение. Карты (или «Функции») имеют уникальные имена (или ключи), которые, конечно, соответствуют значениям. Последовательности расширяют карты (где каждый ключ является целым числом> 0). Сумки (или множественные наборы) расширяют Карты (где каждая клавиша является элементом, а каждое значение - количество раз, которое элемент появляется в сумке).
Эта структура позволила бы пересечение, объединение и т. Д. Ряда «коллекций». Следовательно, иерархия должна быть:
Sun / Oracle / Java ppl - пожалуйста, сделайте это правильно в следующий раз. Спасибо.
источник
Если вы посмотрите на соответствующую структуру данных, вы легко сможете догадаться, почему
Map
она не является частьюCollection
. КаждыйCollection
хранит одно значение, где в качествеMap
пары ключ-значение. Поэтому методыCollection
интерфейса несовместимы сMap
интерфейсом. Например, уCollection
нас естьadd(Object o)
. Что бы такое внедрение вMap
. Не имеет смысла иметь такой метод вMap
. Вместо этого у нас естьput(key,value)
метод вMap
.Тот же аргумент относится и к
addAll()
,remove()
иremoveAll()
методы. Таким образом, основная причина заключается в разнице в способе хранения данных вMap
иCollection
. Также, если вы помнитеCollection
интерфейс, реализованныйIterable
интерфейсом, т.е. любой интерфейс с.iterator()
методом должен возвращать итератор, который должен позволять нам перебирать значения, хранящиеся вCollection
. Теперь, что такой метод вернул бы дляMap
? Ключевой итератор или итератор значения? Это тоже не имеет смысла.Существуют способы, с помощью которых мы можем перебирать хранилища ключей и значений в a,
Map
и это является частьюCollection
фреймворка.источник
There are ways in which we can iterate over keys and values stores in a Map and that is how it is a part of Collection framework.
Можете ли вы показать пример кода для этого?add(Object o)
будет добавитьEntry<ClassA, ClassB>
объект. АMap
можно считатьCollection of Tuples
На самом деле, если бы это было так
implements Map<K,V>, Set<Map.Entry<K,V>>
, то я склонен согласиться .. Это кажется даже естественным. Но это не очень хорошо работает, верно? Допустим, у нас естьHashMap implements Map<K,V>, Set<Map.Entry<K,V>
, иLinkedHashMap implements Map<K,V>, Set<Map.Entry<K,V>
т.д ... это все хорошо, но если бы у вас былоentrySet()
, никто не забудет реализовать этот метод, и вы можете быть уверены, что вы можете получить entrySet для любой карты, в то время как это не так, если вы надеетесь что разработчик реализовал оба интерфейса ...Причина, по которой я не хочу этого,
interface Map<K,V> extends Set<Map.Entry<K,V>>
заключается в простом, потому что будет больше методов. А ведь это разные вещи, верно? Также очень практично, если я попалmap.
в IDE, я не хочу видеть.remove(Object obj)
, и.remove(Map.Entry<K,V> entry)
потому что я не могу сделатьhit ctrl+space, r, return
и быть с этим покончено.источник
Map<K,V>
не должен распространяться,Set<Map.Entry<K,V>>
так как:Map.Entry
s с тем же ключом к тому жеMap
, ноMap.Entry
s с тем же ключом к тому жеSet<Map.Entry>
.источник
Прямо и просто. Коллекция - это интерфейс, который ожидает только один объект, тогда как для карты требуется два.
источник