One often sees the advice that variables should be declared with some interface, not the implementing class. For example:
List<Integer> list = new ArrayList<>();
However, say I am using this list for an algorithm that really depended on the O(1) random access of an ArrayList
(e.g. Fisher-Yates shuffling). In that case, the key abstraction that ArrayList
represents for me is its array-like nature, not just its List nature. In other words, if someone came along and changed list
to a LinkedList
, this would be problematic, even though the code would compile. In such a case, is it considered ok to have the declaration use the implementation type?, e.g.:
ArrayList<Integer> list = new ArrayList<>();
Like a class, an interface can have methods and variables, but the methods declared in an interface are by default abstract (only method signature, no body).
If you declare a variable as final, it is mandatory to initialize it before the end of the constructor. If you don't you will get a compilation error.
An interface is declared by using the interface keyword. It provides total abstraction; means all the methods in an interface are declared with the empty body, and all the fields are public, static and final by default.
No, every class should not have an interface. It's overkill squared. You use an interface when you need to abstract what's done from how it's done, and you're certain that the implementation can change.
To emphasize what Oliver Charlesworth said in the comment: The most crucial difference whether this information is public or not.
From the way how the question is written, it seems like you're talking about a field (and not a method parameter or return value). And a private field is, per definition, an implementation detail, and you may make it arbitrarily specific. So it would be feasible to declare it as an ArrayList
- although, strictly speaking, this is not relevant. To phrase it that way: You said
if someone ... changed
list
to aLinkedList
, this would be problematic,...
The one who can change the declaration from
private List<T> list = new ArrayList<T>();
to
private List<T> list = new LinkedList<T>();
can also change the declaration from
private ArrayList<T> list = new ArrayList<T>();
to
private LinkedList<T> list = new LinkedList<T>();
The only practical way to prevent this would be to add this (important) implementation detail as a comment, e.g.
/**
* The list that stores ... whatever.
*
* This list should have a complexity of O(1) for random access,
* because ...
*/
private final List<T> list = new ArrayList<T>();
(This could also be enforced by internally passing the list to a method that expects it to be a RandomAccess
. This was proposed by AlexR, but referring to public
methods. For private
methods, even this won't prevent someone from changing the method signature, if the intention and the reasons for requiring RandomAccess
are not documented).
I think that using interfaces is still very important. You case is very special but there is a way to solve it without usage of concrete classes. There is interface named RandomAccess
. It is tag interface that does not declare methods but it should be used by implementors or List
that do provide randome access to elements.
So, you can define your method that requires random access list as following:
public <E, L extends List<E> & RandomAcess>void algorithm(L list);
You will not be able to pass linked list to this method, but ArrayList
will work. As you an expect now you can change implemtation of list without changing your algorithm. For example you can use thread safe CopyOnWriteArrayList
that will allow yo to make you processing multithreaded without explicit syncrhonized
statements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With