Nuestro team de expertos pasados varios días de trabajo y recopilación de de información, dimos con los datos necesarios, esperamos que te resulte útil para tu trabajo.
Solución:
No hay diferencia entre los objetos; usted tiene un HashMap
en ambos casos. Hay una diferencia en el interfaz tienes al objeto. En el primer caso, la interfaz es HashMap
, mientras que en el segundo es Map
. Pero el objeto subyacente es el mismo.
La ventaja de usar Map
es que puede cambiar el objeto subyacente para que sea un tipo diferente de mapa sin romper su contrato con ningún código que lo esté usando. Si lo declaras como HashMap
, debe cambiar su contrato si desea cambiar la implementación subyacente.
Ejemplo: digamos que escribo esta clase:
class Foo
private HashMap things;
private HashMap moreThings;
protected HashMap getThings()
return this.things;
protected HashMap getMoreThings()
return this.moreThings;
public Foo()
this.things = new HashMap();
this.moreThings = new HashMap();
// ...more...
La clase tiene un par de mapas internos de string-> objeto que comparte (a través de métodos de acceso) con subclases. Digamos que lo escribo con HashMap
s para empezar porque creo que esa es la estructura apropiada para usar al escribir la clase.
Más tarde, Mary escribe código subclasificando. Ella tiene algo que necesita hacer con ambos things
y moreThings
, así que, naturalmente, lo pone en un método común, y usa el mismo tipo que usé en getThings
/getMoreThings
al definir su método:
class SpecialFoo extends Foo
private void doSomething(HashMap t)
// ...
public void whatever()
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
// ...more...
Más tarde, decido que en realidad es mejor si uso TreeMap
en lugar de HashMap
en Foo
. Yo actualizo Foo
, cambiando HashMap
para TreeMap
. Ahora, SpecialFoo
ya no se compila porque rompí el contrato: Foo
solía decir que siempre HashMap
s, pero ahora proporciona TreeMaps
en lugar de. Entonces tenemos que arreglar SpecialFoo
ahora (y este tipo de cosas pueden propagarse a través de una base de código).
A menos que tuviera una muy buena razón para compartir que mi implementación estaba usando un HashMap
(y eso sucede), lo que debí haber hecho fue declarar getThings
y getMoreThings
como solo regresando Map
sin ser más específico que eso. De hecho, salvo una buena razón para hacer otra cosa, incluso dentro de Foo
Probablemente debería declarar things
y moreThings
como Map
, no HashMap
/TreeMap
:
class Foo
private Map things; // <== Changed
private Map moreThings; // <== Changed
protected Map getThings() // <== Changed
return this.things;
protected Map getMoreThings() // <== Changed
return this.moreThings;
public Foo()
this.things = new HashMap();
this.moreThings = new HashMap();
// ...more...
Note como estoy usando ahora Map
en todas partes que puedo, solo siendo específico cuando creo los objetos reales.
Si hubiera hecho eso, Mary habría hecho esto:
class SpecialFoo extends Foo
private void doSomething(Map t) // <== Changed
// ...
public void whatever()
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
... y cambiando Foo
no hubiera hecho SpecialFoo
dejar de compilar.
Las interfaces (y clases base) nos permiten revelar solo lo necesario, manteniendo nuestra flexibilidad bajo las sábanas para realizar cambios según corresponda. En general, queremos que nuestras referencias sean lo más básicas posible. Si no necesitamos saber que es un HashMap
, solo llámalo un Map
.
Esta no es una regla ciega, pero en general, codificación a la interfaz más general va a ser menos frágil que codificar algo más específico. Si hubiera recordado eso, no habría creado un Foo
que preparó a Mary para el fracaso con SpecialFoo
. Si María había recordado eso, entonces, a pesar de que lo arruiné Foo
, ella habría declarado su método privado con Map
en lugar de HashMap
y mi cambio Foo
El contrato no habría afectado su código.
A veces no puedes hacer eso, a veces tienes que ser específico. Pero a menos que tenga una razón para estarlo, diríjase hacia la interfaz menos específica.
Map es una interfaz que implementa HashMap. La diferencia es que en la segunda implementación su referencia al HashMap solo permitirá el uso de funciones definidas en la interfaz del Mapa, mientras que la primera permitirá el uso de cualquier función pública en HashMap (que incluye la interfaz del Mapa).
Probablemente tendrá más sentido si lee el tutorial de interfaz de Sun
Map tiene las siguientes implementaciones:
-
HashMap
Map m = new HashMap();
-
LinkedHashMap
Map m = new LinkedHashMap();
-
Mapa del árbol
Map m = new TreeMap();
-
WeakHashMap
Map m = new WeakHashMap();
Suponga que ha creado un método (esto es solo un pseudocódigo).
public void HashMap getMap()
return map;
Suponga que los requisitos de su proyecto cambian:
- El método debe devolver el contenido del mapa: es necesario volver
HashMap
. - El método debería devolver el mapa keyestá en orden de inserción - Necesita cambiar el tipo de devolución
HashMap
paraLinkedHashMap
. - El método debería devolver el mapa keyestá en orden: es necesario cambiar el tipo de devolución
LinkedHashMap
paraTreeMap
.
Si su método devuelve clases específicas en lugar de algo que implementa el Map
interfaz, tienes que cambiar el tipo de retorno de getMap()
método cada vez.
Pero si usa la función de polimorfismo de Java, y en lugar de devolver clases específicas, use la interfaz Map
, mejora la reutilización del código y reduce el impacto de los cambios de requisitos.
Si te gustó nuestro trabajo, tienes la libertad de dejar una reseña acerca de qué le añadirías a este tutorial.