Es gibt keinen Unterschied zwischen den Objekten; Sie haben HashMap<String, Object>in beiden Fällen eine. Es gibt einen Unterschied in der Schnittstelle, die Sie zum Objekt haben. Im ersten Fall ist die Schnittstelle HashMap<String, Object>, im zweiten Fall Map<String, Object>. Das zugrunde liegende Objekt ist jedoch dasselbe.
Der Vorteil der Verwendung Map<String, Object>besteht darin, dass Sie das zugrunde liegende Objekt in eine andere Art von Karte ändern können, ohne Ihren Vertrag mit Code zu brechen, der es verwendet. Wenn Sie dies als deklarieren HashMap<String, Object>, müssen Sie Ihren Vertrag ändern, wenn Sie die zugrunde liegende Implementierung ändern möchten.
Beispiel: Nehmen wir an, ich schreibe diese Klasse:
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...
}
Die Klasse verfügt über einige interne Zuordnungen von Zeichenfolgen-> Objekten, die sie (über Zugriffsmethoden) mit Unterklassen teilt. Nehmen wir an, ich schreibe es zunächst mit HashMaps, weil ich denke, dass dies die geeignete Struktur für das Schreiben der Klasse ist.
Später schreibt Mary Code in Unterklassen. Sie hat etwas , das sie mit den beiden tun muss thingsund moreThings, so natürlich macht sie , dass in einer gemeinsamen Methode, und sie verwendet den gleichen Typ I verwendeten getThings/ getMoreThingsbei der Definition ihrer Methode:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Später entscheide ich, dass es eigentlich besser ist, wenn ich TreeMapanstelle von HashMapin verwende Foo. Ich aktualisiere Foound wechsle HashMapzu TreeMap. Jetzt wird SpecialFoonicht mehr kompiliert, weil ich den Vertrag gebrochen habe: FooFrüher hieß es HashMaps, aber jetzt TreeMapsstattdessen. Also müssen wir jetzt Abhilfe schaffen SpecialFoo(und so etwas kann sich durch eine Codebasis kräuseln).
Wenn ich nicht einen wirklich guten Grund hatte zu teilen, dass meine Implementierung ein verwendet HashMap(und das passiert), hätte ich deklarieren getThingsund getMoreThingseinfach zurückkehren sollen, Map<String, Object>ohne spezifischer zu sein. In der Tat, abgesehen von einem guten Grund, etwas anderes zu tun, Foosollte ich selbst innerhalb wahrscheinlich erklären thingsund moreThingsals Map, nicht 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...
}
Beachten Sie, wie ich jetzt Map<String, Object>überall verwende, wo ich kann, und nur dann spezifisch bin, wenn ich die tatsächlichen Objekte erstelle.
Wenn ich das getan hätte, hätte Mary dies getan:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
... und das Ändern Foohätte nicht dazu geführt, SpecialFoodass das Kompilieren aufgehört hätte.
Über Schnittstellen (und Basisklassen) können wir nur so viel wie nötig preisgeben und unsere Flexibilität unter Verschluss halten, um gegebenenfalls Änderungen vorzunehmen. Im Allgemeinen möchten wir, dass unsere Referenzen so einfach wie möglich sind. Wenn wir nicht wissen müssen, dass es ein ist HashMap, nennen Sie es einfach ein Map.
Dies ist keine blinde Regel, aber im Allgemeinen ist die Codierung für die allgemeinste Schnittstelle weniger spröde als die Codierung für etwas Spezifischeres. Wenn ich mich daran erinnert hätte, hätte ich keine geschaffen Foo, die Mary zum Scheitern verurteilt hätte SpecialFoo. Wenn Mary sich daran erinnert hätte, hätte sie, obwohl ich es vermasselt Foohabe, ihre private Methode mit Mapstatt deklariert, HashMapund der Vertrag meiner Änderung Foohätte sich nicht auf ihren Code ausgewirkt.
Manchmal kann man das nicht, manchmal muss man spezifisch sein. Aber wenn Sie keinen Grund dazu haben, gehen Sie zur am wenigsten spezifischen Schnittstelle.