В чем разница между объектами HashMap и Map в Java?
в чем разница между следующими картами, которые я создаю (в другом вопросе люди ответили, используя их, казалось бы, взаимозаменяемо, и мне интересно, насколько они отличаются):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
13 ответов:
нет никакой разницы между объектами; у вас есть
HashMap<String, Object>в обоих случаях. Есть разница в интерфейс у вас есть объект. В первом случае, интерфейсHashMap<String, Object>, тогда как во втором этоMap<String, Object>. Но основной объект тот же самый.преимущества использования
Map<String, Object>это то, что вы можете изменить базовый объект, чтобы быть другим видом карты, не нарушая свой контракт с любым кодом, который его использует. Если вы его объявите какHashMap<String, Object>, вы должны изменить свой контракт, если вы хотите изменить базовую реализацию.
пример: Допустим, я пишу этот класс:
class Foo { private HashMap<String, Object> things; private HashMap<String, Object> moreThings; protected HashMap<String, Object> getThings() { return this.things; } protected HashMap<String, Object> getMoreThings() { return this.moreThings; } public Foo() { this.things = new HashMap<String, Object>(); this.moreThings = new HashMap<String, Object>(); } // ...more... }класс имеет несколько внутренних карт string - > object, которые он разделяет (через методы доступа) с подклассами. Допустим, я пишу его с
HashMaps Для начала, потому что я думаю, что это подходящая структура для использования при написании класса.позже, Мэри пишет код подкласса его. У нее есть что-то, что она должна сделать с обоими
thingsиmoreThings, поэтому, естественно, она помещает это в общий метод, и она использует тот же тип, который я использовал наgetThings/getMoreThingsпри определении ее методом:class SpecialFoo extends Foo { private void doSomething(HashMap<String, Object> t) { // ... } public void whatever() { this.doSomething(this.getThings()); this.doSomething(this.getMoreThings()); } // ...more... }позже, я решаю, что на самом деле, это лучше, если я использую
TreeMapвместоHashMapнаFoo. Я обновляюFoo, измененияHashMapдоTreeMap. Теперь,SpecialFooбольше не компилируется, потому что я нарушил контракт:Fooраньше говорили, что это обеспеченоHashMaps, но теперь он обеспечиваетTreeMapsвместо. Так что мы должны исправитьSpecialFooтеперь (и такого рода вещи могут пульсировать через кодовую базу).если у меня не было действительно веской причины для обмена, что моя реализация использует
HashMap(и это действительно происходит), то, что я должен был сделать, было объявитьgetThingsиgetMoreThingsкак только возвращениеMap<String, Object>не будучи более конкретным, чем это. На самом деле, за исключением хорошей причины, чтобы сделать что-то еще, даже в пределахFooя должен, вероятно, объявитьthingsиmoreThingsкакMap, а неHashMap/TreeMap:class Foo { private Map<String, Object> things; // <== Changed private Map<String, Object> moreThings; // <== Changed protected Map<String, Object> getThings() { // <== Changed return this.things; } protected Map<String, Object> getMoreThings() { // <== Changed return this.moreThings; } public Foo() { this.things = new HashMap<String, Object>(); this.moreThings = new HashMap<String, Object>(); } // ...more... }обратите внимание, как я сейчас, используя
Map<String, Object>везде, где я могу, только будучи конкретным, когда я создаю фактические объекты.если бы я это сделал, то Мэри сделала бы вот что:
class SpecialFoo extends Foo { private void doSomething(Map<String, Object> t) { // <== Changed // ... } public void whatever() { this.doSomething(this.getThings()); this.doSomething(this.getMoreThings()); } }...и меняется
Fooне было быSpecialFooостановка компиляции.интерфейсы (и базовые классы) раскроем ровно столько, сколько нужно, сохраняя наши гибкость под крышками для внесения изменений по мере необходимости. В общем, мы хотим, чтобы наши ссылки были как можно более простыми. Если нам не нужно знать, что это
HashMap, просто называют этоMap.это не слепое правило, но в целом,кодирование на самый общий интерфейс будет менее хрупким, чем кодирование на что-то более конкретное. Если бы я помнил это, я бы не создал
Fooэто настроило Мэри на неудачу сSpecialFoo. Если Мария вспомнил об этом, хотя я все испортилFoo, она бы объявила свой личный метод сMapвместоHashMapи мои измененияFooконтракт не повлиял бы на ее код.иногда вы не можете этого сделать, иногда вы должны быть конкретными. Но если у вас нет причин, чтобы быть, ошибитесь в сторону наименее конкретного интерфейса.
карта - это интерфейс, который HashMap реализует. Разница заключается в том, что во второй реализации ваша ссылка на HashMap позволит использовать только функции, определенные в интерфейсе карты, в то время как первая позволит использовать любые публичные функции в HashMap (который включает интерфейс карты).
Это, вероятно, будет иметь больше смысла, если Вы читаете Sun's interface tutorial
Я просто собирался сделать это как комментарий к принятому ответу, но он стал слишком напуганным (Я ненавижу не иметь разрывов строк)
Ах, так разница в том, что в в общем, карта имеет определенные методы связанный с ней. но есть различные способы или создание карты, такие как Хэшмап, так и эти разные способы предоставляют уникальные методы, которые не все карты.
точно--и вы всегда хотите использовать самый общий интерфейс, который вы только можете. Рассмотрим ArrayList vs LinkedList. Огромная разница в том, как вы их используете, но если вы используете "список", вы можете легко переключаться между ними.
фактически, вы можете заменить правую часть инициализатора более динамическим оператором. как насчет чего-то вроде этого:
List collection; if(keepSorted) collection=new LinkedList(); else collection=new ArrayList();таким образом, если вы собираетесь заполнить коллекцию сортировкой вставки, вы будете использовать связанный список (сортировка вставки в список массивов является преступной.) Но если вам не нужно держать его сортируются и просто добавляются, вы используете ArrayList (более эффективный для других операций).
Это довольно большая растяжка здесь, потому что коллекции не являются лучшим примером, но в OO design одна из самых важных концепций-использование фасада интерфейса для доступа к различным объектам с одним и тем же кодом.
изменить ответ на комментарий:
Что касается вашего комментария к карте ниже, да, используя интерфейс "карта" ограничивает вас только теми методы, Если вы не отбрасываете коллекцию из Map в HashMap (что полностью побеждает цель).
часто то, что вы будете делать, это создать объект и заполнить его, используя его конкретный тип (HashMap), в каком-то методе "создать" или "инициализировать", но этот метод вернет "карту", которую больше не нужно манипулировать как хэш-карту.
Если вам когда-нибудь придется бросить кстати, вы, вероятно, используете неправильный интерфейс или ваш код недостаточно хорошо структурирован. Обратите внимание, что допустимо, чтобы один раздел вашего кода рассматривал его как "HashMap", а другой-как "карту", но это должно течь "вниз". так что вы никогда не бросаете.
Также обратите внимание на полу-аккуратный аспект роли указанных интерфейсов. LinkedList делает хороший стек или очередь, ArrayList делает хороший стек, но ужасная очередь (опять же, удаление вызовет сдвиг всего списка), поэтому LinkedList реализует интерфейс очереди, ArrayList-нет.
карта, имеющая следующие реализации,
HashMap
Map m = new HashMap();LinkedHashMap
Map m = new LinkedHashMap();Дерево
Map m = new TreeMap();WeakHashMap
Map m = new WeakHashMap();предположим, что вы создали один метод (это просто код spudo).
public void HashMap getMap(){ return map; }предположим, что требования к проекту меняются каждый раз следующим образом:
- метод должен возвращать содержимое карты-нужно вернуть
HashMap.- метод должен возвращать ключ карты в порядке вставки-необходимо изменить тип возврата
HashMapдоLinkedHashMap.- метод должен возвращать ключ карты в отсортированном порядке-нужно изменить тип возврата
LinkedHashMapдоTreeMap.если ваш метод возвращает определенные классы вместо
Mapинтерфейс вы должны изменить тип возвращаемогоgetMap()метод каждый раз.но, если вы используете полиморфизм особенность java, вместо возврата конкретного класса используется интерфейс
Map, это приводит к повторному использованию кода и меньшему воздействию, если какие-либо изменения требований.
Как отметили TJ Crowder и Adamski, одна ссылка относится к интерфейсу, другая-к конкретной реализации интерфейса. По словам Джошуа блока, вы всегда должны пытаться кодировать интерфейсы, чтобы позволить вам лучше обрабатывать изменения в базовой реализации-т. е. если HashMap внезапно не был идеальным для вашего решения, и вам нужно было изменить реализацию карты, вы все равно можете использовать интерфейс карты и изменить тип экземпляра.
во втором примере ссылка "карта" имеет тип
Map, который представляет собой интерфейс, реализованныйHashMap(и других видовMap). Этот интерфейс является контракт говоря, что объект отображает ключи к значениям и поддерживает различные операции (например,put,get). Там написано ничего о реализации наMap(в данном случае aHashMap).второй подход, как правило, предпочтительнее, так как вы обычно не хотите предоставьте конкретную реализацию карты методам, использующим
Mapили через определение API.
карта статического типа карты, в то время как HashMap-это динамического типа карты. Это означает, что компилятор будет рассматривать ваш объект map как один из типов Map, даже если во время выполнения он может указывать на любой его подтип.
эта практика программирования по интерфейсам вместо реализаций имеет дополнительное преимущество в сохранении гибкости: вы можете, например, заменить динамический тип карты во время выполнения, если это подтип карты (например LinkedHashMap), и изменить поведение карты на лету.
хорошее эмпирическое правило-оставаться максимально абстрактным на уровне API: если, например, метод, который вы программируете, должен работать на картах, то достаточно объявить параметр как Map вместо более строгого (потому что менее абстрактного) типа HashMap. Таким образом, потребитель вашего API может быть гибким в отношении того, какую реализацию карты они хотят передать вашему методу.
вы создаете одни и те же карты.
но вы можете заполнить разницу, когда вы будете его использовать. В первом случае вы сможете использовать специальные методы HashMap (но я не помню никого действительно полезного), и вы сможете передать его как параметр HashMap:
public void foo (HashMap<String, Object) { ... } ... HashMap<String, Object> m1 = ...; Map<String, Object> m2 = ...; foo (m1); foo ((HashMap<String, Object>)m2);
добавление в топ-проголосовали ответ, и многие из них выше подчеркнув "более универсальный, лучше", хотелось бы немного больше.
Map- это договор, структура, аHashMapэто реализация, предоставляющая свои собственные методы для решения различных реальных проблем: как вычислить индекс, какова емкость и как ее увеличить, как вставить, как сохранить индекс уникальным и т. д.давайте заглянем в исходный код:
In
Mapмы есть методcontainsKey(Object key):boolean containsKey(Object key);JavaDoc:
логическая java.утиль.Карта.containsValue(Object значение)
возвращает true, если эта карта отображает один или более ключей на указанное значение. Более формально возвращает true тогда и только тогда, когда эта карта содержит хотя бы одно сопоставление со значением
vтакое, что(value==null ? v==null : value.equals(v)). Эта операция, вероятно, потребует линейного времени в размере карты для большинства реализаций интерфейса карты.параметры:значение
значение, чье присутствие на этой карте является betested
возвращает:true
если эта карта отображает один или более ключей на указанное
valueThrows:
ClassCastException-если значение имеет неподходящий тип для этой карты (необязательно)
NullPointerException - если указанное значение равно null и эта карта не разрешает значения null (необязательно)
он требует своих реализаций для его реализации, но "как" находится на свободе, только чтобы убедиться, что он возвращается правильно.
In
HashMap:public boolean containsKey(Object key) { return getNode(hash(key), key) != null; }получается, что
HashMapиспользует хэш-код, чтобы проверить, содержит ли эта карта ключ. Таким образом, он имеет преимущество хэш-алгоритма.
Map-это интерфейс, а Hashmap-это класс, который реализует это.
Так что в этой реализации вы создаете те же объекты
HashMap-это реализация Map, поэтому она совершенно одинакова, но имеет метод " clone ()", как я вижу в справочном руководстве))
HashMap<String, Object> map1 = new HashMap<String, Object>(); Map<String, Object> map2 = new HashMap<String, Object>();в первую очередь
Mapэто интерфейс он имеет другую реализацию, как -HashMap,TreeHashMap,LinkedHashMapetc. Интерфейс работает как супер класс для реализации класса. Итак, согласно правилу ООП любой конкретный класс, который реализуетMapэтоMapтакже. Это означает, что мы можем назначить / поставить любойHashMapтип переменнойMapтип переменной без каких-либо типа литья.в этом случае мы можем назначить
map1доmap2без какого-либо кастинга или любой потеря данных -map2 = map1

Comments