Does it make sense to declare private fields using an interface as their type?
Yes it does. For many reasons.
However, in my experience programmers normally declare variables to be of the exact type of the class that will be assigned to them, e.g. HashMap in this case. Why is this?
Until they've fully written the method they don't know what all it will need access to. You could start with the most restrictive interface and switch to less restrictive as needed. But that will work against code completion tools.
Starting with HashMap as HashMap and later switching to the most restrictive interface theoretically produces the same result. And it means, as you think of new things you need from HashMap, they're right there at your fingertips. Problem is, people who work this way sometimes forget to make the switch.
For some it's easier to think of a HashMap as just a HashMap when writing code. After all you have many other things to think about. Even some well trained OOP programmers do this, not because they think it's good practice but because they don't want to be distracted while writing code. This is selfish because it doesn't hurt them nearly as much as it hurts those who come after. Sometimes they meant to take the time to refactor to the interface but never got around to it. Don't look at code written like this as if it was meant to be this way. This is quick and dirty.
But it's private! No getters. No setters.
It's true that being private means this variables type and its very existence is not visible to the outside world unless it is passed into some outside object. Even in that case the parameter of the method / constructor receiving it is the one that most needs to be as high up the inheritance chain as possible. Not the argument (our variable) being passed in.
However, good coding principles aren't just for between objects. Some can save you a lot of hassle just within one method.
Relevant design principles
- Program to an interface, not an implementation
- Role interfaces
- Make decisions in one place
Program to an interface
Say this variable is used in at least one long hard to read method. If it is declared as a map and not something concrete I can instantly tell that I could refactor to any map implementation without even having to read the long method.
If the long method can get by with the variable at an even higher level it should. Do you really need map? Can you get by with one of its super interfaces that exposes less? (Well map doesn't have a super interface but imagine we were talking about list). The less exposed, the higher up it is, the more options you have for hassle free change.
Make decisions in one place
Since I've already shown that I don't want to even read this long ugly method, should it come as a surprise that I don't want to go through it changing a bunch of hashmaps to map? (or some other implementation if I feel like passing on the misery). I don't. I really don't. Please don't make me. Please?