I have a couple of Java classes that extend various implementations of the generic List interface. They simply log anything that is added to the List.
The LoggingArrayList is shown below. As the name suggests, it extends ArrayList. The LoggingLinkedList class is identical except that it extends LinkedList.
My main objective is to avoid having to duplicate all of the common code just so that I can use a different base class. I'm trying to adhere to the DRY principle (Don't Repeat Yourself) as much as possible.
First of all, please don't suggest a better way of logging. That's not at all my real application. It's just an easy way to demo the problem I'm having.
I have two closely related questions. The first one is the question in the title. How can I reference a "super" method in a Java class that implements an interface but does not extend another class?
The LoggingArrayList class as shown below works fine but when I change the class declaration from ...extends ArrayList to ...implements List then the three references to super.method() are no longer callable, hence my first question.
A good answer to my second question will almost make the first question moot. The second question is this: Is there a way to declare an abstract base class or perhaps an interface that extends List with default implementations of the various add() methods so that I can simply extend that abstract base class or implement that interface and only specify what kind of List will be the basis for the concrete class?
For example, I'd like to do something like this:
interface LoggingList<T extends Object, L extends List<T>> extends L
{
// overloaded methods go here as shown below
// with overloaded methods declared as default for the interface
}
...then I could simply implement LoggingList one time for each concrete implementation of List without duplicating all of the common code. The concrete classes might then look something like this, with no additional code needed inside their curly braces:
public class LoggingArrayList<T extends Object> implements LoggingList<T, ArrayList<T>> {}
public class LoggingLinkedList<T extends Object> implements LoggingList<T, LinkedList<T>> {}
The problem is that the interface definition as I have proposed it is invalid (won't compile) and also, the references to super.method(s) in the code shown below are unavailable unless I make LoggingList an abstract subclass instead of an interface and then I end up right back where I am now.
Thanks in advance for any ideas on how to accomplish my DRY goal.
Here's my whole LoggingArrayList class.
public abstract class LoggingArrayList<T extends Object>
extends ArrayList<T>
{
protected void log(T e)
{
System.out.println(e == null ? "null" : e.toString());
}
@Override
public boolean add(T e) {
log(e);
// How do I reference a super.method()
// in a class that implements an interface
// but does not extend another class?
return super.add(e);
}
@Override
public boolean addAll(Collection<? extends T> clctn) {
boolean anyChanges = false;
for(T e : clctn)
{
// ensure that we call our overridden version of add()
// so it gets logged.
anyChanges = anyChanges || add(e);
}
return anyChanges;
}
@Override
public boolean addAll(int i, Collection<? extends T> clctn) {
for(T e : clctn)
{
// ensure that we call our overridden version of add()
// so it gets logged.
add(i, e);
i++; // keep the inserted elements in their original order
}
return !clctn.isEmpty();
}
@Override
public T set(int i, T e) {
log(e);
// How do I reference a super.method()
// in a class that implements an interface
// but does not extend another class?
return super.set(i, e);
}
@Override
public void add(int i, T e) {
log(e);
// How do I reference a super.method()
// in a class that implements an interface
// but does not extend another class?
super.add(i, e);
}
}