Abstract Class Program in Java
Abstract Class Program in Java
Abstraction is a technique by which a developer hides the implementation details from the user and shows only the functionality.It is not only confined to the programming. In the real-world also abstraction is achieved.
For example, a person presses a switch to turn on the light. However, the person does not know the technicality behind it. The person only knows that when the switch is pressed, the bulb glows. Similarly, when the brakes are applied by the driver to stop a car, the car stops. The driver, who applied the brakes, does not know the physics of car brakes. He only knows the car has to stop if the brakes are applied.
In Java, abstraction is achieved through interfaces or abstract classes. We will discuss interfaces in the next topic. In this section, we will discuss abstract class in Java and the usage of abstract classes in programming.
What is an abstract class?
In Java, when the declaration of a class contains the keyword abstract, that class is an abstract class. An abstract class can have constructors, static methods, final methods, fields, and abstract methods. An abstract class can never be instantiated.
What is an abstract method?
An abstract method is a method that is declared with the abstract keyword. It never contains the definition of the method. Classes inheriting an abstract class either give the definition of the abstract method or should be declared as abstract. It is not mandatory for an abstract class to contain an abstract method. Also, if a method is declared as abstract, it cannot be static. Similarly, if a method is declared as static, it cannot be abstract. In other words, static and abstract keywords do not go side by side in a method declaration.
The following Java code illustrates how to create an abstract class.
FileName: AbstractClassExample.java
// Ab is an abstract class abstract class Ab { // constructor of class Ab Ab() { } // A static method display() static void display() { System.out.println("In the display method of the abstract class."); } // an abstract method abstract void foo(); } public class AbstractClassExample { // driver method public static void main(String argvs[]) { // calling the static method of the abstract class Ab.display(); } }
Output:
In the display method of the abstract class.
Explanation: Static methods are also the class methods. This is because we can invoke a static method using the class name. The same thing we are doing with the method display(). Note that instantiation is prohibited in the abstract class, not the usage of the class name. Therefore, we are able to invoke the method display() using the class name Ab. Apart from the abstract and static methods, we can also add instance methods in an abstract class.
Usage of the abstract class in real world
Abstract classes are mainly used where it is known what needs to be done, but it is not known how it is done. We usually leave the accomplishment part to the classes that inherit from the abstract class. The following example demonstrates the same.
FileName: PaymentMainClass.Java
// payment is the abstract class abstract class Payment { Payment() { System.out.println("A child class object is created"); } // pay() method is abstract. // Classes inheriting the Payment class have to implement this method abstract void pay(); } // class UPIPayment inheriting the class Payment // and implementing the method pay class UPIPayment extends Payment { @Override void pay() { System.out.println("Paying using UPI"); } } // class CardPayment inheriting the class Payment // and implementing the method pay class CardPayment extends Payment { @Override void pay() { System.out.println("Paying using debit or credit card"); } } // class IMPSPayment inheriting the class Payment // and implementing the method pay class IMPSPayment extends Payment { @Override void pay() { System.out.println("Paying using IMPS"); } } // class RTGSPayment inheriting the class Payment // and implementing the method pay class RTGSPayment extends Payment { @Override void pay() { System.out.println("Paying using RTGS"); } } // class NEFTPayment inheriting the class Payment // and implementing the method pay class NEFTPayment extends Payment { @Override void pay() { System.out.println("Paying using NEFT"); } } // class ChequePayment inheriting the class Payment // and implementing the method pay class ChequePayment extends Payment { @Override void pay() { System.out.println("Paying using cheque"); } } // class CashPayment inheriting the class Payment // and implementing the method pay class CashPayment extends Payment { @Override void pay() { System.out.println("Paying using cash"); } } public class PaymentMainClass { // driver method public static void main(String argvs[]) { // creating an object of UPIPayment UPIPayment upiObj = new UPIPayment(); // paying using UPI upiObj.pay(); // creating an object of UPIPayment CardPayment cardObj = new CardPayment(); // paying using Card cardObj.pay(); // creating an object of UPIPayment IMPSPayment impsObj = new IMPSPayment(); // paying using IMPS impsObj.pay(); // creating an object of UPIPayment RTGSPayment rtgsObj = new RTGSPayment(); // paying using RTGS rtgsObj.pay(); // creating an object of UPIPayment NEFTPayment neftObj = new NEFTPayment(); // paying using NEFT neftObj.pay(); // creating an object of UPIPayment ChequePayment chequeObj = new ChequePayment(); // paying using Cheque chequeObj.pay(); // creating an object of UPIPayment CashPayment cashObj = new CashPayment(); // paying using Cash cashObj.pay(); } }
Output:
A child class object is created Paying using UPI A child class object is created Paying using debit or credit card A child class object is created Paying using IMPS A child class object is created Paying using RTGS A child class object is created Paying using NEFT A child class object is created Paying using cheque A child class object is created Paying using cash
Explanation: In the abstract class, we set the template of what needs to be done, i.e., for making a payment, we have declared a method pay(). The different types of payment classes give the definition of the method pay() in a different way. Thus, the implementation varies from one payment child class to another payment child class. Also, every-time an of different payment class is created, the constructor of the abstract class is invoked (see the output). This means the behavior of a constructor remains the same in the abstract class too.
Abstract Class and the Open Close Principle
Not only in the payment field, in drawing geometrical shapes, for calculating the rate of interest of different banks, and in many more fields, we can declare an abstract class containing abstract methods and let the inheriting class decide how to implement those abstract methods. This serves two purposes: one is the extension of code to handle future requirements (open for extension), which becomes very easy, and another is the base class that is not disturbed while doing the extension (closed for modification). Let’s understand with the help of the following code.
FileName: InterestMainClass.Java
// Interest is the abstract class abstract class Interest { // an abstract method for the bank name abstract void bankName(); // an abstract method for calculating rate of interest abstract void rateOfInterest(); } // class for Bank Of Badoda class BankOfBaroda extends Interest { // defining the abstract methods of the Interest class void bankName() { System.out.println("The bank name is Bank of Badoda."); } void rateOfInterest() { System.out.println("Its rate of interest is: " + 6 + "% \n"); } } // class for Punjab National Bank class PunjabNationalBank extends Interest { // defining the abstract methods of the Interest class void bankName() { System.out.println("The bank name is Punjab National Bank."); } // defining the abstract methods of the Interest class void rateOfInterest() { System.out.println("Its rate of interest is: " + 7.5 + "% \n"); } } // class for HDFC Bank class HDFCBank extends Interest { // defining the abstract methods of the Interest class void bankName() { System.out.println("The bank name is HDFC Bank."); } // defining the abstract methods of the Interest class void rateOfInterest() { System.out.println("Its rate of interest is: " + 8.3 + "% \n"); } } public class InterestMainClass { // a static method for displaying rate of interest and // names of different banks static void display(Interest obj) { // calling the method bankName() of the concerned class obj.bankName(); // calling the method rateOfInterest() of the concerned class obj.rateOfInterest(); } // driver method public static void main(String argvs[]) { // Creating entities of different banks BankOfBaroda barodaObj = new BankOfBaroda(); PunjabNationalBank pnbObj = new PunjabNationalBank(); HDFCBank hdfcObj = new HDFCBank(); // invoking method display to // print bank names and their rate of interests // on the console display(barodaObj); display(pnbObj); display(hdfcObj); } }
Output:
The bank name is Bank of Baroda. Its rate of interest is: 6% The bank name is Punjab National Bank. Its rate of interest is: 7.5% The bank name is HDFC Bank. Its rate of interest is: 8.3%
Explanation: The above-written code is quite flexible in handling future requirements. For example, suppose HDFC bank is closed forever. Then, we can comment out the class, which is handling the bank HDFC, i.e., class HDFCBank. Also, we have to comment out the object creation of the class HDFCBank in the driver method. The rest of the other code remains intact (closed for modification). Similarly, if we have to add another bank and its rate of interest (extending the code to incorporate more banks, i.e., open for extension), we can create its class and extend it from the abstract class Interest. This time also, we did not touch the classes of other banks.