Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>There is no difference between the objects; you have a <code>HashMap&lt;String, Object&gt;</code> in both cases. There is a difference in the <em>interface</em> you have to the object. In the first case, the interface is <code>HashMap&lt;String, Object&gt;</code>, whereas in the second it's <code>Map&lt;String, Object&gt;</code>. But the underlying object is the same.</p> <p>The advantage to using <code>Map&lt;String, Object&gt;</code> is that you can change the underlying object to be a different kind of map without breaking your contract with any code that's using it. If you declare it as <code>HashMap&lt;String, Object&gt;</code>, you have to change your contract if you want to change the underlying implementation.</p> <hr> <p>Example: Let's say I write this class:</p> <pre><code>class Foo { private HashMap&lt;String, Object&gt; things; private HashMap&lt;String, Object&gt; moreThings; protected HashMap&lt;String, Object&gt; getThings() { return this.things; } protected HashMap&lt;String, Object&gt; getMoreThings() { return this.moreThings; } public Foo() { this.things = new HashMap&lt;String, Object&gt;(); this.moreThings = new HashMap&lt;String, Object&gt;(); } // ...more... } </code></pre> <p>The class has a couple of internal maps of string->object which it shares (via accessor methods) with subclasses. Let's say I write it with <code>HashMap</code>s to start with because I think that's the appropriate structure to use when writing the class.</p> <p>Later, Mary writes code subclassing it. She has something she needs to do with both <code>things</code> and <code>moreThings</code>, so naturally she puts that in a common method, and she uses the same type I used on <code>getThings</code>/<code>getMoreThings</code> when defining her method:</p> <pre><code>class SpecialFoo extends Foo { private void doSomething(HashMap&lt;String, Object&gt; t) { // ... } public void whatever() { this.doSomething(this.getThings()); this.doSomething(this.getMoreThings()); } // ...more... } </code></pre> <p>Later, I decide that actually, it's better if I use <code>TreeMap</code> instead of <code>HashMap</code> in <code>Foo</code>. I update <code>Foo</code>, changing <code>HashMap</code> to <code>TreeMap</code>. Now, <code>SpecialFoo</code> doesn't compile anymore, because I've broken the contract: <code>Foo</code> used to say it provided <code>HashMap</code>s, but now it's providing <code>TreeMaps</code> instead. So we have to fix <code>SpecialFoo</code> now (and this kind of thing can ripple through a codebase).</p> <p>Unless I had a really good reason for sharing that my implementation was using a <code>HashMap</code> (and that does happen), what I should have done was declare <code>getThings</code> and <code>getMoreThings</code> as just returning <code>Map&lt;String, Object&gt;</code> without being any more specific than that. In fact, barring a good reason to do something else, even within <code>Foo</code> I should probably declare <code>things</code> and <code>moreThings</code> as <code>Map</code>, not <code>HashMap</code>/<code>TreeMap</code>:</p> <pre><code>class Foo { private Map&lt;String, Object&gt; things; // &lt;== Changed private Map&lt;String, Object&gt; moreThings; // &lt;== Changed protected Map&lt;String, Object&gt; getThings() { // &lt;== Changed return this.things; } protected Map&lt;String, Object&gt; getMoreThings() { // &lt;== Changed return this.moreThings; } public Foo() { this.things = new HashMap&lt;String, Object&gt;(); this.moreThings = new HashMap&lt;String, Object&gt;(); } // ...more... } </code></pre> <p>Note how I'm now using <code>Map&lt;String, Object&gt;</code> everywhere I can, only being specific when I create the actual objects.</p> <p>If I had done that, then Mary would have done this:</p> <pre><code>class SpecialFoo extends Foo { private void doSomething(Map&lt;String, Object&gt; t) { // &lt;== Changed // ... } public void whatever() { this.doSomething(this.getThings()); this.doSomething(this.getMoreThings()); } } </code></pre> <p>...and changing <code>Foo</code> wouldn't have made <code>SpecialFoo</code> stop compiling.</p> <p>Interfaces (and base classes) let us reveal <em>only as much as is necessary</em>, keeping our flexibility under the covers to make changes as appropriate. In general, we want to have our references be as basic as possible. If we don't need to know it's a <code>HashMap</code>, just call it a <code>Map</code>.</p> <p>This isn't a blind rule, but in general, <em>coding to the most general interface</em> is going to be less brittle than coding to something more specific. If I'd remembered that, I wouldn't have created a <code>Foo</code> that set Mary up for failure with <code>SpecialFoo</code>. If <em>Mary</em> had remembered that, then even though I messed up <code>Foo</code>, she would have declared her private method with <code>Map</code> instead of <code>HashMap</code> and my changing <code>Foo</code>'s contract wouldn't have impacted her code.</p> <p>Sometimes you can't do that, sometimes you have to be specific. But unless you have a reason to be, err toward the least-specific interface.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload