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.