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 HashMap
s, 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 things
und moreThings
, so natürlich macht sie , dass in einer gemeinsamen Methode, und sie verwendet den gleichen Typ I verwendeten getThings
/ getMoreThings
bei 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 TreeMap
anstelle von HashMap
in verwende Foo
. Ich aktualisiere Foo
und wechsle HashMap
zu TreeMap
. Jetzt wird SpecialFoo
nicht mehr kompiliert, weil ich den Vertrag gebrochen habe: Foo
Früher hieß es HashMap
s, aber jetzt TreeMaps
stattdessen. 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 getThings
und getMoreThings
einfach zurückkehren sollen, Map<String, Object>
ohne spezifischer zu sein. In der Tat, abgesehen von einem guten Grund, etwas anderes zu tun, Foo
sollte ich selbst innerhalb wahrscheinlich erklären things
und moreThings
als 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 Foo
hätte nicht dazu geführt, SpecialFoo
dass 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 Foo
habe, ihre private Methode mit Map
statt deklariert, HashMap
und der Vertrag meiner Änderung Foo
hä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.