Monday, July 17, 2023

Why is Abstract class Important in Java? [Example]

Abstract class is a special class in Java, it can not be instantiated and that's why can not be used directly. At first concept of abstraction, abstract class and interface all look useless to many developers, because you can not implement any method in an interface, you can not create an object of the abstract class, so why do you need them. Once they face biggest constant of software development, yes that is CHANGE, they understand how abstraction at the top level can help in writing flexible software. A key challenge while writing software (Java Programs, C++ programs) is not just to cater today's requirement but also to ensure that nurture requirement can be handled without any architectural or design change in your code. In short, your software must be flexible enough to support future changes.

The abstract class and inheritance collectively ensures that most of the code are written using abstract and higher level classes, so that it can leverage Inheritance and Polymorphism to support future changes.

This is actually one of the most useful design principle, also known as "Programming for interfaces rather than implementation".  Abstract class and abstract method are two ways through which Java assist you on coding at a certain level of abstraction.

We will look at syntax level details, capability, and limitation of abstract class at the later half of article, but you must understand why an abstract class is important. More importantly, why you, a Java programmer, must understand motive and use of an abstract class.

From my years of experience, I can say that making a class at first an interface or abstract class is a good practice, it will not only help you to test your code quickly by supplying mock objects, but also help you to write code at the certain level of abstraction.

In this article, we will understand why we need abstract class and abstract method and learn how to use them by writing a simple example.




Where do you use Abstract Class in Java

Apart from conventional use of Abstract class to write flexible code, there are several clever uses of abstract class, which ensures certain best practices are followed. Most of these usage take advantage of important properties of abstract class e.g. you can not create object of abstract class. If you do so, compiler will flag an error. 

One of the clever use of abstract class I have seen is to use abstract class in conjunction with Factory method pattern to ensure that your client always use Factory method to create instance of object, instead of accidentally calling constructor. By making Product class abstract, compiler will track down any call to new Product() and force them to use factory methods like makeProduct() or getProduct()

One of the best example of this technique is EnumSet class in JDK, unlike other implementation of Set interface, EnumSet is abstract, which ensures that you always make use of factory methods like EnumSet.of() instead of doing new EnumSet()

Imagine, if EnumSet was not abstract and you are using it first time, how would you have created instance of EnumSet? Factory method or Constructor? Always remember, compiler is your best friend, it finds bugs for you, So make full use of your best friend. A best practice can be forgotten but a rule enforced by compiler will never.



Why Abstract class is Important in Java

Though there are lot of difference between abstract class and interface, key thing to remember is that they both provides abstraction. Let's take an example, you need to design a program, which can produce reports for employees e.g. how many hours they worked and how much they are paid every month. Let's assume that currently your organization only has permanent employees, which are paid monthly. 

You know that and you write code based upon that, after sometime your company started recruiting contract employees, which are paid at hourly rate rather than monthly salary. Now, if you need to rewrite your program to support this, they your program is not flexible enough. 

On the other hand, if you just needs to write some code to plug this new type of employee into system, they your program is very much flexible and maintainable. If you would have known about abstract class, you would have made Employee an abstract class and methods like salary() abstract, because that is what varies between different types of employees. 

Now introducing a new type of Employee would be cakewalk, all you need to do is to create another subclass of Employee to represent ContractEmployee, and their salary method return salary based upon a number of hours they had worked multiplied by their hourly rate. So, you get the idea right, we code at a certain level of abstraction, which allows us to accommodate new changes in our system.



Abstract class and Method Example in Java

Let's see another example of abstract class and method, this one is a rather tasty example. I love fruits, they are tasty, provide vitamins and you don't need to cook them to eat. All you do, you take fruit, wash them then you either cut them or peel them before eating. 

Our example is based on this behavior. We have created an abstract class Fruit, which contains some concrete behavior like color, whether it's a seasonal fruit or not, and abstract behavior called prepare().

Abstract class and method Example in Java

 In order to serve fruits, we need to prepare them for eating, which involves either cutting them in slices or peel them. We have two concrete implementations of Fruit class, Mango and Banana, I chose these two because first, they are my favorites, and second they have different methods of preparing them. You cut mangoes but you peel bananas.

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Java Program to demonstrate what is abstract class and 
 * abstract method in Java, how to use
 * them, when to use them with a practical example.
 *
 * @author Javin Paul
 */
public class AbstractClassDemo{

    public static void main(String args[]) {
        Fruit mango = new Mango(Color.YELLOW, true); // mango is seasonal
        Fruit banana = new Banana(Color.YELLOW, false); 
        // banana is not seasonal

        List<Fruit> platter = new ArrayList<Fruit>();
        platter.add(mango);
        platter.add(banana);
        serve(platter);
    }

    public static void serve(Collection<Fruit> fruits) {
        System.out.println("Preparing fruits to serve");
        for (Fruit f : fruits) {
            f.prepare();
        }
    }
}


/*
 * Abstract class to represent Fruit, defined only essential
 * properties of Fruit here and make things abstract which
 * is different for different fruits.
 */
abstract class Fruit {
    private Color color;
    private boolean seasonal;

    public Fruit(Color color, boolean seasonal) {
        this.color = color;
        this.seasonal = seasonal;
    }

   /*
    * This is an abstract method, see it doesn't have method body, 
    * only declaration
    */
    public abstract void prepare();

    public Color getColor() {
        return color;
    }

    public boolean isSeasonal() {
        return seasonal;
    }
}


/*
 * A concrete class to extend Fruit, since Mango IS-A Fruit
 * extending Fruit is justified. it got all properties of
 * fruit, and it defines how to prepare mango for eating.
 */
class Mango extends Fruit {

    public Mango(Color color, boolean seasonal) {
        super(color, seasonal);
    }

    @Override
    public void prepare() {
        System.out.println("Cut the Mango");
    }
}


/*
 * Another concrete class to extend Fruit.
 */
class Banana extends Fruit {

    public Banana(Color color, boolean seasonal) {
        super(color, seasonal);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void prepare() {
        System.out.println("Peal the Banana");
    }
}

Output:
Preparing fruits to serve
Cut the Mango
Peal the Banana

Things to remember about abstract class and method in Java

Application of something e.g. abstract class is work of creativity and takes time to master, but remembering syntax and important properties is rather easy, which eventually help you to attain the first goal. As a Java programmer, you must always remember following things about abstract class and method.

1) You cannot create instance of an abstract class in Java. For example if a class ABC is abstract than code like Abc instance = new ABC() will result in compile time error. Think of two scenarios where you can advantage of this property, always remember a weapon can be used for both attack and defence. One scenario I have already discussed here is to making sure that your client always use factory method to create object instead of directly calling constructor.

2) To create a concrete class by extending abstract class, you must override all abstract method. For example if a class ABC has an abstract method abc() then a class EFG, which extends ABC must override abc() to be a concrete class i.e. whose instance can be created. 

On related note, always use @Override annotation while overriding a method in Java. It not only help your fellow programmers to see your intent but also helps your friend compiler to find subtle mistakes which can easily ship due to blind faith on your other friend IDE's content assist. Believe me its too easy to import a class with same name but from different package with code auto-completion feature of modern IDEs.

3) A class can be abstract even without any abstract method. Though, its not mandatory (not ensured by any compiler rule) to have abstract method inside abstract class, but this is not advisable, because there is no point doing it. 

If your class don't have any abstract behaviour (behaviour which changes between different types) then its good candidate of being a concrete class rather than abstract. There is only one case where I think abstract class without abstract method can be used is when you need a marker class instead of marker interface, but to be frank, I have yet to find a practical use case. Though thinking a class as abstract at start can be good for discovering some level of abstraction.

4) Both top level and nested class can be make abstract in Java, no restriction on this from the Java programming language.


That's all about the Abstract class in Java. Always remember that anything abstract (e.g. abstract class or abstract method) is not complete in Java, and you must extend the abstract class and override the abstract method to make use of that class. Remember, Abstraction is very important to design flexible systems. Flexibility comes from using interfaces and abstract class at top level and leverage inheritance and Polymorphism to supply different implementation without changing the code which uses them.



Other Java programming and OOP tutorials You may like


27 comments:

  1. There is no need to use abstract class in JDK 8. We can implement the default method in interface itself.

    ReplyDelete
    Replies
    1. Not completely true...you may want state included as part of your superclass in which case you would still use an abstract class.

      Delete
  2. "you can not implement any method in interface"

    With default method you can.

    ReplyDelete
  3. Is this compulsory to use abstract method in abstract class or we can use abstract method any where

    ReplyDelete
    Replies
    1. Yes, its compulsory to use abstract method in abstract class . This abstract method should be override in subclass which extend Abstract class. This provide full abstraction properties.
      And You can use abstract method anywhere inside abstract class.

      Delete
  4. Good explanation!

    ReplyDelete
  5. Respected Sir/Madam,

    1. I create one abstract class like Phone and declare 3 methods.

    1.1 public void calling(){System.out.println("Calling")}
    1.2 public abstract moving();
    1.3 public abstract dancing();

    2. I create one more abstract class PhoneFeature extends Phone
    2.1 define only moving method in this class.

    3. Create concrete class MPhone extends PhoneFeature

    is any way to show only calling and moving function when i will create object of MPhone class. I do not want to show dancing method in MPhone.

    ReplyDelete
  6. The sentences can not work well below :
    List<Fruit> platter = new ArrayList<Fruit>();
    I don't know the reason , could you give me some explanation ?

    ReplyDelete
    Replies
    1. Why it will not work well. Can you please provide more explanation to your question ?

      Delete
  7. Why don't we create instance in abstract class?If we create, what'll the effect?

    ReplyDelete
  8. Why don't we create object of abstract class?If we create,what'll the effect?

    ReplyDelete
    Replies
    1. Hello Vivudh, compiler doesn't allow you to create object of abstract class, if you do, code will not compile e.g.

      AbstractClass obj = new AbstractClass();

      is illegal in Java. It make sense because Abstract class is incomplete.

      Delete
  9. Fruit mango = new Mango(Color.YELLOW, true); fruit is abstract class how we created its object here???

    ReplyDelete
  10. Is there any disadvantage for abstraction?

    ReplyDelete
    Replies
    1. Yes, a lot of abstraction makes code complex due to lot of indirection. A right level of Abstraction make code flexible and readable at same time.

      Delete
  11. we can achieve this functionality using concrete class there no need to use abstract class here is example.

    So I am not clear Why Abstract class is Important?



    Class1.cs

    using System;

    namespace AbstractExample
    {
    public class Mango : Fruit
    {
    public Mango(string color, bool seasonal) : base(color, seasonal)
    {
    Console.WriteLine("Mango");
    }

    public override void Prepare()
    {
    Console.WriteLine("Cut the mango!");
    }
    }

    public class Banana : Fruit
    {
    public Banana(string color, bool seasonal) : base(color, seasonal)
    {
    Console.WriteLine("Banana");
    }
    public override void Prepare()
    {
    Console.WriteLine("peel the Banana!");
    }
    }

    public class Fruit
    {

    private readonly string color;
    private readonly bool seasonal;
    public Fruit(string Color, bool Seasonal)
    {
    Console.WriteLine("Fruit" + Color + " Seasonal " + Seasonal);
    color = Color;
    seasonal = Seasonal;
    }

    public virtual void Prepare() { }
    public string GetColor()
    { return color; }
    public bool IsSeasonal()
    { return seasonal; }



    }
    }


    Program.cs

    using AbstractExample;
    using System;
    using System.Collections.Generic;
    using System.Threading;

    namespace TestAppp
    {

    class Program
    {
    static void Main(string[] args)
    {
    Fruit mango = new Mango("orange",true);
    Fruit banana = new Banana("yello", false);

    List fruits = new List();
    fruits.Add(mango);
    fruits.Add(banana);

    serve(fruits);

    Console.WriteLine("Hello World!");

    }

    public static void serve(List fruits)
    {
    foreach (var item in fruits)
    {
    item.Prepare();
    }
    }
    }
    }

    ReplyDelete
    Replies
    1. In real coding, most of the time you need to write extensible code because of your future enhancement. When you code using concrete classes there is no place for future hooks. Abstract classes help you to cope up with change.

      Delete
    2. Then my friend, you didn't understood the concept of abstraction.

      Delete
  12. Thank you for posting such an informative and useful article about Abstract Classes.

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.