What is the importance of abstract class that extends from another abstract class

It's totally fine when one abstract class extends another abstract class. It just means that it details the behavior of the new class based on the behavior of the old class. But it's still not a full object to be used, because some of its behavior is still unknown.

In analogy to the real world.
Imagine you have a class Vehicle. It can be any vehicle: car, plane, bus, bicycle, whatever. This is your abstract class. Can you use it now? No, because you do not know whether you have to push the pedals or turn the wheel.
Now you create another class, say, Car extends Vehicle. Can you use it now? Probably, but you still do not know whether it's a truck or a passenger car. But you know that it has a steering wheel.
And finally, when you create one more class, say, MySuperPassengerCar extends Car you know exactly what object this is, how it can be used and what methods it has.


Abstract class defines abstract methods. Any class extending another class enhances the super class by addimg more behavior. If the child class is abstract, it can add some abstract behavior.

Abstract methods are like Contracts. The other code can consume the existing code and can depend on it. The concrete class are bound to follow the contract by providing the implementation.

Lets see it with an example below.

public abstract class SuperAbstract {
      public void nonAbstract(){
            // some code
      }
      public abstract void contract();
}

public abstract class SubAbstract extends SuperAbstract{
       public void additionalNonAbstract()
             // some code
        }
        public abstract void additionalContract();
 }

public class Concrete extends SubAbstract{
       public void contract(){
             // implementation
       }
       public void additionalContract(){
               //implementation
       }
}

// although below is allowed and sometimes when we use an external library then this is one of the way but still this is not a good practice. 
// dependencies should be on abstractions only and not on concrete implementation
public abstract class AnotherAbstract extends Concrete{
       public void someMethod(){
             //some code
       }
       public abstract void oneMoreContract();
}

public class ConcreteA extends AnotherAbstract{
        public void oneMoreContract(){
               //some implementation
        }
}

Now Note that in all we have defined 3 contracts and ConcreteA has all the implementations. Also note that as Concrete provides implementations for methods contract and additionalContract hence those implementations are inherited by ConcreteA

Consumer code can easiely depend upon the abstraction. Lets see it in user code (consumer code)

  public class Consumer{
      public void m1(SuperAbstract c)
             c.contract();
             c.nonAbstract();
     }
     public void m2(AnotherAbstract c){
          c.contract();
          c.nonAbstract();
          c.oneMoreContract();
          c.additionalContract();
    }
 }

Now lets see the wiring code providing the dependencies

 public class Main{
       public static void main(String[] args){
            Consumer c = new Consumer();
             c.m1(new Concrete());
             c.m1(new ConcreteA());
             c.m2(new ConcreteA());
     }
}