The reason is Liskov substitution principle. Directly quoted what was said.
Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.
Simple explanation
Map
is an interface
- And an
interface
is a contract
While using a Map
we confirms that, we are using the contract of what a Map
is supposed to do.
For example
doSomething(Map<String, String> map)
doSomething(TreeMap<String, String> map)
doSomething(Map<String, String> map)
gives option to use any implementation which confirm the contract of Map
allowing any of its subtype to work.
Whether doSomething(TreeMap<String, String> map)
accepts any subtype of TreeMap
. But TreeMap
is not a contract so any subtype of TreeMap
can violates its signature/behavior(methods actually). Thus making TreeMap
less preferable compare to Map
. Composition over inheritance can give u more idea about this.