Abstract classes usually have partial or no implementation. On the other hand, concrete classes always have full implementation of its behavior.Unlike concrete classes, abstract classes cannot be instantiated. Therefore abstract classes have to be extended in order to make them useful. Abstract classes may contain abstract methods, but concrete classes can’t. When an abstract class is extended, all methods (both abstract and concrete) are inherited. The inherited class can implement
any or all the methods. If all the abstract methods are not implemented,then that class also becomes an abstract class.
The only real difference is that a concrete class can be instantiated because it provides (or inherits) the implementation for all of its methods. An abstract class cannot be instantiated because at least one method has not been implemented.
Abstract classes are meant to be extended. If they provide any implementation detail, it can be reused by all child classes. A special case is the pure abstract class, which provides no implementation at all. These classes do not help with code reuse, which makes them fundamentally different. This difference is described by the two types of inheritance:
- Implementation inheritance – provides a mechanism for code reuse.
- Interface inheritance – provides a mechanism for subtyping.
If Class B extends Class A, that does not necessarily mean that B is an A. It might just mean that B inherits some code from A. It’s not always clear, and some languages conflate this with subtyping.
Java is an example of a language that provides a different construct for subtyping, called an interface. Interfaces are basically pure abstract classes. If Class B implements Interface A, then B is an A.
When a language decouples implementation inheritance from interface inheritance, it becomes possible to treat certain problems differently. For example:
- Java sidesteps the complexity of multiple inheritance by prohibiting a class from having two superclasses. However, a class is free to implement any number of interfaces.
- It’s easier to follow the principle of favoring composition over inheritance. Extending too many classes can lead to complex class hierarchies, but implementing too many interfaces isn’t as much of a problem. When it comes to tracing the flow of execution through a program, interfaces can’t complicate the issue because they don’t include any executable code.