You can always rewrite an abstract class plus subclasses, without using an abstract class. You cannot always rewrite interfaces plus implementations as abstract classes. Therefore abstract classes are more limited. Their advantage is that they're easy to teach.
Another construct that's easy to teach, but causes problems in larger programs, is 'goto'. (Java doesn't support goto anyway). So just because something is easy to teach, doesn't mean it's going to be that useful.
I generally define interfaces for everything, and then when appropriate provide abstract implementations of those interfaces. This gives the choice to concrete classes to extend from an abstract class or completely re-implement the interface/contract. Either way, calling code only needs to depend on the interface, which is something that can be defined very early on and is not tied to a specific implementation. [ April 27, 2007: Message edited by: Andy Morris ]