Below is the diagram, where, if we just consider the implementations of List,
enter image description here
AbstractList
maintains the core behavior of list. To introduce the new implementationclass MyList
(say) one can inheritAbstractList
and override(if necessary) required methods. By extendingAbstractList
. Additionally,class MyList
is obeying the contract to behave like a list.class MyList extends AbstractList{..}
Users can use collection hierarchy, as,
AbstractList l = new ArrayList<String>(); l.add("one"); //execute ArrayList's add method
A class can also maintain composition relation with any list implementation(at runtime), by having
AbstractList l;
as member, that gets populated at runtime, with any list implementation.
So,
I would like to understand the clear reason, Why additionally interface List<E>
is introduced?
note1: Intention is to understand, how to use interface. This not a duplicate question, because both abstract class and interface are used.I did not use the word 'instead of' or 'rather'
note2: Let us not get into java-8 default methods, as above collection hierarchy was designed with whatever was provided till java-7
3 Answers 3
Your question seems to stem from the wrong assumption that every List
is also a subclass of AbstractList
. While AbstractList
offers versatile base implementations for a lot of methods, there might be reasons not to use this option.
It’s hard to find an example when looking to the public
API only, but there is one: CopyOnWriteArrayList
.
You will find much more once you understand that not every implementation is public
, e.g. by looking at Collections.unmodifiableList
and
Collections.synchronizedList
, both returning implementations not inheriting from AbstractList
for a good reason. They have base classes which are more suitable to their task, UnmodifiableList
extends UnmodifiableCollection
and SynchronizedList
extends SynchronizedCollection
.
There can be other, application-specific reasons not to subclass AbstractList
, in the end, the decision to make the entire Collection
-API interface
-based is fundamental and there is no reason to make an exception for List
. It’s not different to why you should use the Collection
interface instead of AbstractCollection
or the Set
interface instead of AbstractSet
...
Regarding how to use it... If it is about parameters or heap variables which ought to offer the maximum flexibility, of course, you should always use the least specific type that is required for the operation, e.g. the List
interface, if it is required that the provided Collection
has List
semantic. As said, there are List
types which do not extend AbstractList
.
If it is about local variables within an implementation code, you might declare a variable to match the type of the actual implementation, e.g. ArrayList<X> l=new ArrayList<>();
to reduce the number of different types which occur in this code. But that still implies that there is no reason to refer to AbstractList
. The only place where a reference is to AbstractList
is feasible is in the extends AbstractList
clause...
-
1)
java.util.Collections
is container of all innerstatic class
data models and algo. Why would it sit underAbstractList
? So, yes you are right, this static impl has to program on interfaces. ##2) If implementations likeCopyOnWriteArrayList
are sitting in subpackg (java.util.concurrent
), then yes,CopyOnWriteArrayList
has to program on interface as I said in this comment. Perfect answer!!!!overexchange– overexchange2015年07月07日 03:32:08 +00:00Commented Jul 7, 2015 at 3:32 -
one supplementary. Do you think the way we use interface
Comparable
,Callable
&ActionListener
is different from usage of interfaceList
,Set
Collection
? How do you see the difference?overexchange– overexchange2015年07月07日 03:52:50 +00:00Commented Jul 7, 2015 at 3:52 -
Comparable
,Callable
&ActionListener
have only a single abstract method, thus, there is little sense in providing an abstract base class. Since Java 8, such interfaces are called functional interfaces and can be implemented using a lambda expression. Now that interfaces can havedefault
methods, you’ll have to think about whether an interface is basically a function, i.e. has one primary abstract method, as then, you might want to providedefault
methods for all others. However, note thatAbstractList
maintains mutable state, i.e. themodCount
.Holger– Holger2015年07月07日 08:04:14 +00:00Commented Jul 7, 2015 at 8:04 -
Further,
AbstractList
is a skeleton for certain kind of list implementation (i.e. compare toAbstractSequentialList
), thus is not that open to arbitraryinterface
implementations. It’s useful for a lot of implementations but not for all. That’s the reason whyUnmodifiableList
andSynchronizedList
are not subclasses ofAbstractList
(in contrast toEmptyList
), not because they are nested types ofCollections
but because theAbstractList
’s base implementation is not suitable for their purpose.Holger– Holger2015年07月07日 08:07:55 +00:00Commented Jul 7, 2015 at 8:07
In both of your code snippets, the use of AbstractList
is discouraged.1 The correct usage is to put the new instance of list in a List
variable.
The abstract classes AbstractList
and AbstractSequentialList
are provided for the convenience of implementers (i.e. library writers) of list-like containers, by providing default implementations(*) for some of the instance methods, in an effort to reduce code duplication.
(*)There is an ongoing, legitimate debate on what are the (i) preferred-, (ii) tolerable- and (iii) discouraged-ways of providing default implementations of instance methods in the Java language. Please see some of the other questions asked by overexchange for a starting point.
Every list-like container must implement the List
interface directly or indirectly, for them to be usable by other applications in a list-like manner. Inheritance from AbstractList
or AbstractSequentialList
is optional.
Likewise, applications that would like to accept a list-like container should accept a List
. It should not require an AbstractList
or AbstractSequentialList
because it would disqualify some list-like containers.
As to the motivation for naming the interface List
as is, it is likely2 the decision of some influential Java founding fathers that decided that interfaces shall not have any naming decorations that indicate they are interfaces (i.e. not backed by any concrete implementations). That position is debatable but it will stay with the Java language forever.
1 "discouraged" is used as an euphemism for "plainly wrong."
2 Citation needed. Feel free to edit this post to add the necessary reference, or to remove this paragraph if this is incorrect.
-
3Key point: if you extend AbstractList, you can't extend another class. If you want to implement list and extend something else - you can't unless there is a list interface.user40980– user409802015年07月05日 03:09:53 +00:00Commented Jul 5, 2015 at 3:09
-
it would disqualify some list-like containers.? I did not get you.overexchange– overexchange2015年07月05日 08:59:57 +00:00Commented Jul 5, 2015 at 8:59
-
1@overexchange with gnat's example - how would you implement
class Book extends Content implements List<Page>
without being able to implement a List as an interface? You would have to have Content extend AbstractList - which doesn't necessarily make sense. AbstractList contains common tools for implementing a list. It also implements List. But there are things that don't need AbstractList that want to implement a List that need to extend something that shouldn't extend AbstractList. So you have the List interface.user40980– user409802015年07月05日 12:46:45 +00:00Commented Jul 5, 2015 at 12:46 -
@MichaelT If there are things that don't need
AbstractList
, override it.overexchange– overexchange2015年07月05日 12:51:15 +00:00Commented Jul 5, 2015 at 12:51 -
1@overexchange more importantly - don't extend things that have no bearing on the class you are writing.user40980– user409802015年07月05日 12:52:33 +00:00Commented Jul 5, 2015 at 12:52
I would like to understand the clear reason, Why additionally interface List is introduced?
In Java, types form a directed acyclic graph, but classes form a tree. As such, types are strictly more flexible than classes. When designing APIs, you should prefer uses non-class types as much as possible for your parameters and your return types. And pretty much your only choice in Java for a non-class type is an interface.
In other words, interfaces are nicer for users of your types.
However (at least prior to Java 8), if you actually want these types to have an implementation, you need a (possibly abstract) class. So classes are nicer for implementors of your types.
In order to satisfy both users and implementors, the designers of the List API provided both a List
interface and an AbstractList
abstract class.
Funnily enough, today with Java 8, interfaces can have so called "default implementations", thus removing the need for the AbstractList
abstract class. So your question should be phrased the other way: "Why was the additional abstract class AbstractList
introduced?" and the answer would have been "due to historical reasons, old Javas did not have default methods."
-
you mean: "Trees are DAGs with the restriction that a child can only have one parent.", But what is the advantage of DAG formation with
AbstractList
implementinginterface List
in addition to extendingAbstractCollection
?overexchange– overexchange2015年07月05日 09:09:12 +00:00Commented Jul 5, 2015 at 9:09 -
interfaces are nicer for users of your types.? you mean, If one introduces a new class hierarchy, users had to get access to that new class hierarchy via their interfaces? Is that the reason we have
interface List<E>
?overexchange– overexchange2015年07月05日 09:19:39 +00:00Commented Jul 5, 2015 at 9:19 -
forming DAGs:
implements Comparable
is a relevant example. For me, It is clear whyComparable
is an interface?overexchange– overexchange2015年07月05日 09:41:19 +00:00Commented Jul 5, 2015 at 9:41 -
Also, interfaces define object types, classes define abstract data types, so, if you want to do object-oriented programming in Java, you must use only interfaces as types, you cannot use anything else (classes or primitives) as types. This means: types of locals, fields, static fields, method parameters, method return types, the argument to an
instanceof
or cast operator, and the type argument to a generic interface can only be interfaces. Classes can only be used as factories, i.e. the only place a class is allowed to appear is directly next to anew
. Nowhere else.Jörg W Mittag– Jörg W Mittag2015年07月05日 09:54:33 +00:00Commented Jul 5, 2015 at 9:54 -
3This is explained much better than I could ever hope to achieve in On Understanding Data Abstraction, Revisited by William R. Cook. It uses Java for the examples, but it applies just as well to C# or any other language.Jörg W Mittag– Jörg W Mittag2015年07月05日 11:47:57 +00:00Commented Jul 5, 2015 at 11:47
Explore related questions
See similar questions with these tags.
class Book extends Content implements List<Page>
- one couldn't do this with AbstractList, because there would be no way for Book to extend both Content and AbstractList simultaneouslyAbstractList
documentation. Quote: "This class provides a skeletal implementation of the List interface to minimize the effort required to implement this interface backed by a "random access" data store (such as an array)."List
is purely a specification of interface,AbstractList
has behaviour that could conceivably be wrong in some situations. Interface-only inheritance should be preferred when you do not need to inherit behaviour but only need to provide the capability of polymorphism.class MyList
that defines all of the required methods and obeys the general contract is preferred to implement aninterface List
, because theclass Myclass
(some business class) do not need to reside in the above class hierarchy. This has nothing to do with multiple inheritance or polymorphism.