Dla mnie różnica dotyczy dostępnych metod np. List nie ma wszystkich metod ArrayList.
I to jest najlepsze podsumowanie. Jeśli użyjesz metod z ArrayList lub HashMap, ktôrych nie na w List lub Map to przestawienie się na LinkedList czy np. ConcurrenyNavigableHashMap może wymagać więcej zmian w kodzie. Trzymanie się interfejsu przed tym zabezpiecza.
Generalnie warto używać interfejsu w publicznym Api. Kiedy my przyjmujemy jako parametr mapę to lepiej żeby to była Map niż HasMap. Tak samo jak zwracamy lepiej Map niż klasę konkretną. Inaczej może się okazać, że np. przy zmianie z HasMap na ConcurrentNav..Map (wielowątkowa) mysimy poprosić wszystkich korzystających z naszej metody o zmiany w kodzie, albo będziemy musieli wrappować wyniki do HashMapy....
Przy polach prywatnych ( jak w przykładzie) problemu raczej nie ma, bo w razie czego zmian będzie mało i będą w jednym pliku. Robimy to Map
raczej z przyzwyczajenia niž dla większego sensu.
Jeszcze mniejszy zysk ma trzymanie się interfejsów w zmiennych lokalnych. Nie szkodzi, ale i niewiele daje. (Pomijam ludzi kodujących metody na ponad 30 linii).
(Gwizadka1) Są też, dość rzadkie, przypadki,, kiedy to publiczne Api powinno pokazywać implementację, a nie generyczny interfejs, ale to raz na 5 lat sie zdarza.
(gwiazdka2) zasada korzystania z interfejsów jest ogólna i nie dotyczy tylko List i Map. To jest samo sedno istnienia interfejsów. Po to je robimy.