We use abstract classes to implementabstraction in Java. It is one of the key ideas to enable a higher level of abstraction in our code, hide implementation details, enforce polymorphism and promote code reusability.
In Java, abstract classes are similar to regular classes, but they are declared using the abstract keyword and cannot be instantiated. So what is the purpose of an abstract class if it can not be instantiated? Here is an idea: We mostly use an abstract class as a base class for other classes. It provides a set of common attributes and behaviours that the subclasses can inherit and specialize based on their specific requirements.
publicabstractclassAbstractClass{// Fields (if any)// Constructors (if any)// Abstract MethodspublicabstractvoidabstractMethod1();publicabstractvoidabstractMethod2();// Non-Abstract MethodspublicvoidconcreteMethod(){// Implementation}// Other methods (if any)}
Now, one critical question still remains: Why can't an abstract class be instantiated? The idea is: It is often incomplete on its own, mainly because of the presence of abstract methods. Therefore, due to this incomplete or undefined behaviour, attempting to create an instance of the abstract class would not make sense.
abstractclassAnimal{privateString name;publicAnimal(String name){this.name= name;}// Abstract method: No implementation providedpublicabstractvoidmakeSound();publicvoidsleep(){System.out.println(getName()+" is sleeping.");}publicvoideat(){System.out.println(getName()+" is eating.");}// Getter method to retrieve the name of the animalpublicStringgetName(){return name;}}classDogextendsAnimal{publicDog(String name){super(name);}// Implementing the abstract method from the superclass@OverridepublicvoidmakeSound(){System.out.println("Woof woof!");}@Overridepublicvoidsleep(){System.out.println("The dog named "+getName()+" is sleeping.");}}classCatextendsAnimal{publicCat(String name){super(name);}// Implementing the abstract method from the superclass@OverridepublicvoidmakeSound(){System.out.println("Meow meow!");}@Overridepublicvoidsleep(){System.out.println("The cat named "+getName()+" is sleeping.");}}publicclassMain{publicstaticvoidmain(String[] args){// Instantiating Cat using Animal referenceAnimal cat=newCat("Whiskers");// Calling the overridden makeSound() method of Cat cat.makeSound();// Calling the overridden sleep() method of Cat cat.sleep();// Calling the inherited eat() method from Animal cat.eat();// Instantiating Dog using Animal referenceAnimal dog=newDog("Buddy");// Calling the overridden makeSound() method of Dog dog.makeSound();// Calling the overridden sleep() method of Dog dog.sleep();// Calling the inherited eat() method from Animal dog.eat();}}
Let's understand the different concepts used in the above code.
As mentioned above, an abstract method is a method declared in an abstract class that does not have any implementation. It only provides the method signature (name, parameters, and return type) and a contract for the subclasses to implement. Note: Methods declared inside an interface are by default abstract.
abstractclassShape{public abstractdoublecalculateArea();public abstractdoublecalculatePerimeter();}classSquare extends Shape{privatedouble side;publicSquare(double side){this.side= side;}publicdoublecalculateArea(){return side* side;}publicdoublecalculatePerimeter(){return4* side;}}publicclassMain{publicstaticvoidmain(String[] args){ Shape square=newSquare(5);double area= square.calculateArea();double perimeter= square.calculatePerimeter(); System.out.println("Square area: "+ area); System.out.println("Square perimeter: "+ perimeter);}}
A class containing one or more abstract methods must also be declared abstract. On the other hand, an abstract class may or may not contain abstract methods.
abstractclassVehicle{publicvoidstart(){System.out.println("Vehicle started.");}publicvoidstop(){System.out.println("Vehicle stopped.");}}classCarextendsVehicle{// Additional Car-specific methods and fields}
We use abstract methods to enforce certain behaviours in subclasses. So, failure to implement an abstract method in a subclass will result in a compilation error.
For example, when you compile the following code, you will encounter a compilation error because the Square class is attempting to inherit from the Shape abstract class but has not implemented the abstract method calculatePerimeter().
abstractclassShape{publicabstractdoublecalculateArea();publicabstractdoublecalculatePerimeter();}classSquareextendsShape{privatedouble side;publicSquare(double side){this.side= side;}publicdoublecalculateArea(){return side* side;}}publicclassMain{publicstaticvoidmain(String[] args){Shape square=newSquare(5);// Compilation error: Square is not abstract and does not override abstract method calculatePerimeter() in Shapedouble area= square.calculateArea();double perimeter= square.calculatePerimeter();System.out.println("Square area: "+ area);System.out.println("Square perimeter: "+ perimeter);}}
To make the above code work, we either need to override all the abstract methods of the abstract class or, make the subclass abstract.
For example, In the following code, we made the Square class abstract because the calculatePerimeter() method is not implemented in the Square class.
abstractclassShape{publicabstractdoublecalculateArea();publicabstractdoublecalculatePerimeter();}abstractclassSquareextendsShape{privatedouble side;publicSquare(double side){this.side= side;}publicdoublecalculateArea(){return side* side;}// calculatePerimeter() method not implementated}
Note: If there is a need to extend a class with additional behaviour from multiple sources, the use of interfaces or composition might be more appropriate.
Thanks to Ankit Nishad for his contribution in creating the first version of this content. If you have any queries or feedback, please write us at contact@enjoyalgorithms.com. Enjoy learning, enjoy OOPS!