Original answer:
An abstract class allows you to define some shared functionality, while leaving other functionality to be defined by implementations. Thus, abstract classes are useful if you are going to create a family of similar classes that share some functionality but have customizations.
An interface doesn't allow you to define any functionality. It simply defines a set of method signatures that you know can be called on any object of a class that implements that interface.
I'd say the accepted practice is not to use an abstract class to fill the role of an interface. That is, an abstract class should be used for code sharing among related classes that you define, whereas an interface should be used for abstraction.
One reason not to use abstract classes to fill the role of interfaces is that a class cannot inherit from more than one class, but it can implement many interfaces. Thus, using abstract classes limits your design a lot more than using interfaces does.
Edit:
In this particular instance, the difference would be that if you later reassigned l
to contain an object that implements List
but does not derive from AbstractList
, your code will throw an exception. Not all classes that implement List
also extend AbstractList
.
Using AbstractList
limits you to only working with lists that are derived from the core AbstractList
functionality. On the other hand, anyone could write a class that implements List
using totally new code, and if you're using a variable of type List
then you'll still be compatible with their new class that you've never seen before.
The fact that Java's lists are derived from AbstractList
should be treated as an implementation detail that's internal to the Java library, not as an interface that you should code against.