Різниці між об’єктами немає; у вас є 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->, яким він ділиться (за допомогою методу accessor) з підкласами. Скажімо, я пишу це з 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контракт на зміну не вплинув би на її код.
Іноді ти не можеш цього зробити, іноді ти маєш бути конкретним. Але якщо у вас немає причин, помиліться на найменш специфічному інтерфейсі.