Там нет никакой разницы между объектами; у вас есть 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->, который он делит (с помощью методов доступа) с подклассов. Скажем, я пишу его с HashMap
s, чтобы начать с того, что я думаю, что это подходящая структура для использования при написании класса.
Позже Мэри пишет код, подклассифицирующий его. У нее есть то, что ей нужно сделать как с 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
использовал HashMap
, но теперь он предоставляет 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
, который установил Mary для отказа с SpecialFoo
. Если Мэри помнил это, то, хотя я перепутал Foo
, она объявила бы свой частный метод с Map
вместо HashMap
, и мой сменивший контракт Foo
не повлиял бы на ее код.
Иногда вы не можете этого сделать, иногда вы должны быть конкретными. Но если у вас нет оснований быть, перепутайте с наименее определенным интерфейсом.
так что единственное различие заключается в том, что когда я передаю его как параметр, то мне нужно ссылаться на него как на карту, а на другую как HashMap , но они действительно такие же точные типы объектов? –
sepiroth
Да, это тот же самый объект, речь идет о * контракте *, который вы формируете, используя любой код.Я немного уточнил ответ, чтобы уточнить. –
ах, поэтому разница в том, что в целом у Карты есть определенные методы, связанные с ней. но существуют разные способы создания карты, такие как HashMap, и эти разные способы предоставляют уникальные методы, которые не все карты имеют. Поэтому, если я использую Map, я могу использовать только методы Map, но у меня есть HashMap, поэтому на карте видны любые преимущества скорости, преимущества поиска и т. Д. HashMap. И если бы я использовал HashMap, я мог бы использовать эти специальные методы HashMap, и если мне в конечном итоге нужно будет изменить тип карты, это намного больше. – sepiroth