Abstract classes in Java
In this tutorial, we will study the concept of abstract classes in Java—from what they are, how to modify them, how they make smart use of the OOP concepts of Abstraction and Inheritance. Further, we will also compare them with interfaces. We will also have a look at many examples of when to use each of them to ensure a maximum utilisation of OOP concepts while designing our world-changing applications.
Abstract classes
To start, an abstract class is a class that is declared abstract. It may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.
Further, an abstract method is a method that is declared without an implementation (without braces, and followed by a semicolon), like this:
abstract void displacement(double deltaX, double deltaY);
If a class includes abstract methods, then the class itself must be declared abstract, as in:
public abstract class DiscoverObject {
// declare fields
// declare non-abstract methods
abstract void discoverSomething();
}
When an abstract class is subclassed, the subclass must provide implementations for all of the abstract methods in its parent class, otherwise, the subclass itself must be marked abstract as well.
>>> Note: Methods in an interface that are not declared as default or static are implicitly abstract, so the abstract modifier is not used with interface methods. (It can be used, but it is redundant.)
Now, let’s look at some examples of abstract class and how can we subclass it:
abstract public class MyAbstractClass {
abstract public void abstractMethod();
public void implementedMethod() {
System.out.print("This is an implemented method.");
}
final public void finalMethod() {
System.out.print("This is an final method.");
}
}
Notice that abstractMethod() doesn't have any method body. Because of this, you can't do the following:
public class ImplementingClass extends MyAbstractClass {
// ERROR!
}
There's no method that implements abstractMethod()! So there's no way for the JVM to know what it's supposed to do when it gets something like:
new ImplementingClass().abstractMethod().
Here's a correct ImplementingClass.
public class ImplementingClass extends MyAbstractClass {
public void abstractMethod() {
System.out.print("Discovering abstractMethod()");
}
}
Notice that you don't have to define implementedMethod() or finalMethod(). They were already defined by MyAbstractClass.
Here's another correct ImplementingClass.
public class ImplementingClass extends MyAbstractClass {
public void abstractMethod() {
System.out.print("abstractMethod()");
}
public void implementedMethod() {
System.out.print("Overridden!");
}
}
In this case, you have overridden implementedMethod(). However, because of the final keyword, the following is not possible.
public class ImplementingClass extends MyAbstractClass {
public void abstractMethod() {
System.out.print("abstractMethod()");
}
public void implementedMethod() {
System.out.print("Overridden!");
}
public void finalMethod() {
System.out.print("ERROR!");
}
}
You can't do this because the implementation of finalMethod() in MyAbstractClass is marked as the final implementation of finalMethod(): no other implementations will be allowed, ever.
Lastly, you cannot do the following:
public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass {
... // implementation
}
Only one class can be extended at a time. If you need to extend multiple classes, they have to be interfaces. You can do this:
public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB {
... // implementation
}
Here's an example interface:
interface InterfaceA {
void interfaceMethod();
}
This is basically the same as:
abstract public class InterfaceA {
abstract public void interfaceMethod();
}
The only difference is the second way doesn't let the compiler know that it's actually an interface. This can be useful if you want people to only implement your interface and not others. However, as a general beginner rule of thumb, if your abstract class only has abstract methods, you should probably make it an interface.
Composite Design pattern and Abstract classes
The composite pattern can be used when a collection of objects should be treated the same way as one object of the same type. Composite pattern composes objects in terms of a tree structure to represent part as well as the whole hierarchy of levels. This design pattern is a type of structural pattern as this creates a tree structure of group of objects.
Below is an example where this pattern suits well:
public abstract class Shape {
public abstract void Draw();
}
public class Line extends Shape {
public override void Draw() {
// Draw line
}
}
public class Polygon extends Shape {
private List<Line> lines;
@Override
public void Draw() {
for (Shape line : lines) {
line.Draw();
}
}
}
As you can see, the pattern makes it possible for the code dealing with drawing shapes to be unaware of what shape is to be drawn.
Composite can be used when clients should ignore the difference between compositions of objects and individual objects. If programmers find that they are using multiple objects in the same way, and often have nearly identical code to handle each of them, then composite pattern is a good choice; it is less complex in this situation to treat primitives and composites as homogeneous.
>>> static methods cannot be made abstract. Abstract means 'implemented in subclasses', 'static' means 'executed on the class rather than class instances'. To add, you can't override a static method, so making it abstract would be meaningless. Moreover, a static method in an abstract class would belong to that class, and not the overriding class, so it couldn't be used anyway.
Abstract classes and Abstraction
Abstraction is the process of generalization: taking a concrete implementation and making it applicable to different, albeit somewhat related, types of data. "Abstract" is an antonym of "concrete". With abstractions you represent notions and ideas, rather than the concrete way these ideas are implemented. This fits into your understanding of abstraction - you are hiding the details and you only show the interface.
But this also fits with abstract classes—they are not concrete (they can't be instantiated, for one), and they don't specify implementations. They specify abstract ideas that subclasses have to take care of.
Abstract classes, unlike interfaces, are classes. They are more expensive to use, because there is a look-up to do when you inherit from them.
Abstract classes look a lot like interfaces, but they have something more—you can define a behavior for them.
Difference: Abstract class and Interface
Interfaces have following properties:
- Define well known public contract, abilities of the type
- Applicable to show horizontal inheritance, i.e. branching on the first level of inheritance (e.g. ILog to define logging facilities to database, text file, XML, SOAP etc.)
- All members are public
- No implementation allowed
- Inheritance child can have many interfaces to implement
- Useful for third party integration
- Naming usually starts with I
With abstract classes, properties differ as follows:
- Define structure, identity and some default supported behaviour
- Applicable to show vertical inheritance, i.e. deep branching on the several levels
- Members can have different visibility (from public to private)
- You can implement some members (e.g. *Reader classes)
- Inheritance child can have only one base abstract class
When To Use Interfaces
An interface allows somebody to start from scratch to implement your interface or implement your interface in some other code whose original or primary purpose was quite different from your interface. To them, your interface is only incidental, something that you have to add on to the their code to be able to use your package. The disadvantage is every method in the interface must be public. You might not want to expose everything.
When To Use Abstract classes
An abstract class, in contrast, provides more structure. It usually defines some default implementations and provides some tools useful for a full implementation. The catch is, code that uses it must use your class as the base. That may be highly inconvenient if the other programmers wanting to use your package have already developed their own class hierarchy independently. In Java, a class can inherit from only one base class.
When to Use Both
You can offer the best of both worlds, an interface and an abstract class. Implementers can ignore your abstract class if they choose. The only drawback of doing this is that calling methods via their interface name is slightly slower than calling them via their abstract class name.
Conclusion
In this article, we studied the concept of abstract classes in Java. From what they are, how to modify them, how they make smart use of the OOP concepts of Abstraction and Inheritance, and we also compared them with interfaces. We also had a look at many examples of when to use each of them to ensure a maximum utilisation of OOP concepts while designing our world-changing applications.
Please leave a comment below if you have any questions!
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment