Non c'è differenza tra gli oggetti; hai un HashMap<String, Object>in entrambi i casi. C'è una differenza nell'interfaccia che hai con l'oggetto. Nel primo caso, l'interfaccia è HashMap<String, Object>, mentre nel secondo è Map<String, Object>. Ma l'oggetto sottostante è lo stesso.
Il vantaggio dell'utilizzo Map<String, Object>è che puoi modificare l'oggetto sottostante in un diverso tipo di mappa senza rompere il contratto con qualsiasi codice che lo utilizza. Se lo dichiari come HashMap<String, Object>, devi modificare il contratto se desideri cambiare l'implementazione sottostante.
Esempio: diciamo che scrivo questa classe:
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...
}
La classe ha un paio di mappe interne di string-> object che condivide (tramite metodi accessor) con sottoclassi. Diciamo che lo scrivo con HashMaps all'inizio perché penso che sia la struttura appropriata da usare quando si scrive la classe.
Più tardi, Mary scrive il codice subclassandolo. Ha qualcosa che deve fare con entrambi thingse moreThings, quindi, naturalmente, lo mette in un metodo comune e usa lo stesso tipo che ho usato su getThings/ getMoreThingsdurante la definizione del suo metodo:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Più tardi, decido che in realtà, è meglio se uso TreeMapinvece di HashMapin Foo. Aggiornamento Foo, cambiando HashMapin TreeMap. Ora, SpecialFoonon compilare più, perché ho rotto il contratto: era Foosolito dire che forniva HashMaps, ma ora TreeMapsinvece fornisce . Quindi ora dobbiamo risolvere SpecialFoo(e questo genere di cose può incresparsi in una base di codice).
A meno che non avessi una buona ragione per condividere che la mia implementazione stava usando un HashMap(e ciò accade), ciò che avrei dovuto fare era dichiarare getThingse getMoreThingssemplicemente tornare Map<String, Object>senza essere più specifico di così. In effetti, escludendo una buona ragione per fare qualcos'altro, anche all'interno Foodovrei probabilmente dichiarare thingse moreThingscome Map, non 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...
}
Nota come sto usando Map<String, Object>tutto il possibile, essendo specifico solo quando creo gli oggetti reali.
Se l'avessi fatto, allora Mary avrebbe fatto questo:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
... e il cambiamento Foonon avrebbe SpecialFooimpedito la compilazione.
Le interfacce (e le classi di base) ci rivelano solo quanto è necessario , mantenendo la nostra flessibilità sotto le coperte per apportare le modifiche appropriate. In generale, vogliamo che i nostri riferimenti siano il più basilari possibile. Se non abbiamo bisogno di sapere che è un HashMap, chiamalo semplicemente un Map.
Questa non è una regola cieca, ma in generale, la codifica per l'interfaccia più generale sarà meno fragile della codifica per qualcosa di più specifico. Se me lo fossi ricordato, non avrei creato un FooMary con cui Mary avrebbe fallito SpecialFoo. Se Mary lo avesse ricordato, allora anche se avessi sbagliato Foo, avrebbe dichiarato il suo metodo privato Mapinvece di HashMape il mio Foocontratto di modifica non avrebbe avuto alcun impatto sul suo codice.
A volte non puoi farlo, a volte devi essere specifico. Ma a meno che tu non abbia un motivo per esserlo, vai verso l'interfaccia meno specifica.