Search code examples
javaclassoopdesign-patternsabstract-class

Instantiating an abstract class in Java?


I am learning Java and following the book JAVA:The Complete Reference by Herbert Shildt.

I learned about abstract classes in Java, but could not understand reason behind this line:

An abstract class cannot be directly instantiated with new operator.

I searched over web and Stack Overflow and followed these questions: Why can't we instantiate an abstract class in Java? and Why can't we instantiate an interface or an abstract class in java without an anonymous class method?

In one answer, someone wrote as:

Simply, in a good object oriented program, you should never want to instantiate an abstract class or interface. If you do, the design is probably wrong.

I do not understand why it is important not to instantiate an abstract class for good OOP design. If someone can give a good explanation, then please help.


Solution

  • An abstract class should be something that doesn't make sense if it exists completely on its own.

    Take a Vehicle for example. Can you describe a Vehicle without describing a specific type of Vehicle at the same time? No - because Vehicle is just a way of describing common features and behaviours of a group of related objects. Alternatively, you could think of them as concepts.

    Your quote:

    Simply, in a good object oriented program, you should never want to instantiate an abstract class or interface. If you do, the design is probably wrong.

    Is spot on. If you've written an abstract class that you want to instantiate completely on its own, then it isn't an abstract class. If you ever find yourself in this situation, you probably need to carry out another level of abstraction to separate out the abstract parts from the bits that actually start to condense the class into something concrete. The only thing you should want to do with an abstract class is to extend it - to turn it into something less vague (or more concrete if you prefer).

    Of course, Java can seem a little contradictory at times. In fact, writing a constructor for an abstract class is perfectly valid:

    abstract class Vehicle {
    
        // You might have some common variables defined here
    
        Vehicle() { }
    }
    

    At first this seems a little stupid. Why can I write a constructor, which is designed to allow you to instantiate an object, when I'm not allowed to instantiate the class? The compiler will even create a default constructor for you if you don't write one!

    The answer there is that you are allowed to instantiate an abstract class - you're just not allowed to instantiate it directly using the new keyword. But the most important part of abstract classes is that they're designed to be extended.

    When you instantiate a subclass of an abstract class, you either explicitly or implicitly call super(); inside the constructor:

    public class Car extends Vehicle {
        public Car() {
            super(); // If you don't put this here, the compiler will!
        }
    }
    

    This actually makes sense when you think about it - you can't have a Vehicle on it's own, but my car that's sat in the car park is definitely a Vehicle. Once I have a concrete extension to my concept of a Vehicle, Car in this case, then I can have a Vehicle.

    Probably the most useful thing that this enables you to do is create generic collections. Because Vehicle is the superclass of all of the different types of Vehicle, I can say:

    List<Vehicle> vehicles = new ArrayList<>();
    

    Or if you prefer not to/can't use the diamond operator (<>):

    List<Vehicle> vehicles = new ArrayList<Vehicle>();
    

    This allows me to put any type of Vehicle into that collection:

    vehicles.add(new Car());
    vehicles.add(new Van());
    vehicles.add(new Lorry());
    vehicles.add(new Motorcycle());
    // and so on...
    

    Although there are many other advantages to this, too numerous to cover in this answer.