CodeGym/Java Blog/Java Classes/Specific examples of abstract classes in Java
Author
Vasyl Malik
Senior Java Developer at CodeGym

Specific examples of abstract classes in Java

Published in the Java Classes group
members
Hi! In past lessons, we met interfaces and figured out what they're for. Today's topic will echo the previous one. Let's talk about abstract classes in Java. Specific examples of abstract classes in Java - 1

Why classes are called 'abstract'

You probably remember what 'abstraction' is — we've already gone over it. :) If you forgot, fear not. Remember: it's a principle of OOP that says when designing classes and creating objects, we should identify only the entity's main properties and discard the minor. For example, if we're designing a SchoolTeacher class, we hardly need a 'height' property. Indeed, this property is irrelevant for a teacher. But if we're creating a BasketballPlayer class, then growth would be an important characteristic. So listen. An abstract class is as abstract as they come — an unfinished 'blank' for a group of future classes. The blank can't be used as is. It's too 'raw'. But it describes certain state and general behavior that will be possessed by future classes that inherit the abstract class.

Examples of abstract Java classes

Consider a simple example with cars:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
This is what the simplest abstract class looks like. As you can see, it's nothing special :) Why would we need it? First of all, it describes our required entity, a car, in the most abstract way possible. There's a reason why we're using the word abstract. In the real world, there are no 'abstract cars'. There are trucks, race cars, sedans, coupes, and SUVs. Our abstract class is simply a 'blueprint' we will use later to create car classes.
public class Sedan extends Car {

   @Override
   public void gas() {
       System.out.println("The sedan is accelerating!");
   }

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }

}
This is very similar to what we talked about in the lessons on inheritance. But in those lessons, we had a Car class and its methods weren't abstract. But that solution has a number of drawbacks that are fixed in abstract classes. First and foremost, you can't create an instance of an abstract class:
public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
Java's creators specifically designed this 'feature'. Once again, as a reminder: an abstract class is just a blueprint for future 'normal' classes. You don't need copies of the blueprint, right? And you don't create instances of an abstract class :) But if the Car class weren't abstract, we could easily create instances of it:
public class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       // Some logic
   }

    public void brake() {
       // Some logic
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Everything is fine. A car is created.
   }
}
Now our program has some sort of incomprehensible car — it's not a truck, not a race car, not a sedan, and it's totally unclear what it is. This is the very 'abstract car' that doesn't exist in nature. We can provide the same example using animals. Imagine if Animal classes (abstract animals). It's unclear what kind of animal it is, what family it belongs to, and what characteristics it has. It would be strange to see that in your program. There are no 'abstract animals' in nature. Only dogs, cats, foxes, moles, etc. Abstract classes deliver us from abstract objects. They give us basic state and behavior. For example, all cars should have a model, color, and maximum speed, and you should be able to apply the gas and brake. That's it. This is a general abstract plan. Next you design the classes you need. Note: two methods in the abstract class are also designated as abstract, and they don't have any implementation. The reason is the same: abstract classes don't create default behavior for abstract cars. They just indicate what every car should be able to do. However, if you do need default behavior, you can implement methods in an abstract class. Java doesn't prohibit this:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("Gas!");
   }

   public abstract void brake();

   // Getters and setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Console output: “Gas!" As you can see, we've implemented the first method in the abstract class, and not the second. As a result, our Sedan class's behavior is divided into two parts: if you call the gas() method, the call 'rises' up to the Car abstract parent class, but we overrode the brake() method in the Sedan class. This turns out to be very convenient and flexible. But now our class isn't so abstract? After all, half of its methods are implemented. This is actually a very important feature - a class is abstract if at least one of its methods is abstract. One of two methods, or at least one of a thousand methods — it makes no difference. We can even implement all the methods and leave none of them abstract. Then it would be an abstract class without abstract methods. In principle, this is possible, and the compiler won't generate errors, but it's better to avoid it: The word abstract loses its meaning, and your fellow programmers will be very surprised :/ At the same time, if a method is marked with the word abstract, each child class must implement it or declare it as abstract. Otherwise, the compiler will generate an error. Of course, each class can inherit only one abstract class, so in terms of inheritance there's no difference between abstract and ordinary classes. It doesn't matter if we inherit an abstract class or an ordinary one, there can be only one parent class.

Why Java doesn't have multiple inheritance of classes

We've already said that Java doesn't have multiple inheritance, but we haven't really explored why. Let's try to do that now. The fact is that if Java had multiple inheritance, child classes wouldn't be able to decide which specific behavior they should choose. Suppose we have two classes — Toaster and NuclearBomb:
public class Toaster {


 public void on() {

       System.out.println("The toaster is on. Toast is being prepared!");
   }

   public void off() {

       System.out.println("The toaster is off!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Boom!");
   }
}
As you can see, both have an on() method. For a toaster, it starts toasting. For a nuclear bomb, it sets off an explosion. Oops: / Now imagine that you decided (don't ask me why!) to create something in between. And thus you have a MysteriousDevice class! This code, of course, doesn't work, and we only provide it as an example 'but it could be':
public class MysteriousDevice extends Toaster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // So what should happen here? Do we get toast or a nuclear apocalypse?
   }
}
Let's take a look at what we have. The mysterious device simultaneously inherits Toaster and NuclearBomb. Both have on() methods. As a result, if we call the on() method, it's unclear which one should be invoked on the MysteriousDevice object. There's no way the object could ever know. And to top it all off: The NuclearBomb doesn't have an off() method, so if we didn't guess right, it will be impossible to disable the device. Specific examples of abstract classes in Java - 2It is precisely because of this 'confusion', where the object doesn't know what behavior to exhibit, that Java's creators abandoned multiple inheritance. However, you will recall that Java classes can implement multiple interfaces. By the way, in your studies, you've already encountered at least one abstract class! Though maybe you didn't even notice :)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
It's your old friend, the Calendar class. It's abstract and has several children. One of them is GregorianCalendar. You already used it in the lessons about dates. :) Everything seems clear enough. There's just one question: what is the fundamental difference between abstract classes and interfaces anyway? Why did they add both to Java rather than just limiting the language to one? After all, that would have been entirely adequate. We'll talk about this in the next lesson! Until then :)
Comments (17)
  • Popular
  • New
  • Old
You must be signed in to leave a comment
DarthGizka
Level 24 , Wittenberg, Germany
2 June 2021, 19:31
The argument as to why Java doesn't have multiple inheritance is facetious - it applies equally to the implementation of multiple interfaces, which Java does have. And default methods make Java go even more in the direction of real multiple inheritance. It's just that multiple inheritance is somewhat difficult to implement efficiently and bloody darn difficult to *use* correctly. Single inheritance plus multiple interfaces gives you most of what multiple inheritance has to offer, with none (or only very little) of the difficulty that real multiple inheritance tends to pose for the programmer .
Zach
Level 22 , Fort Collins, United States
11 March 2021, 18:34
Should you put abstract parent classes in the same file as your child classes or should they be in the same file such as was written in the lesson?
Gellert Varga
Level 23 , Szekesfehervar, Hungary
10 April 2021, 23:46
I don’t know how professional programmers think it’s good to work. But I have found that both of the following cases work: 1) We put all the classes in one file. But in this case: - Only the class containing the main() method can be marked public! - The file name must be the same as the only public class name. 2) We put each class in its own separate file.
Henrique
Level 41 , São Paulo, Brazil
28 May 2020, 14:41
As Ivaylo asked below, what if our class implements two interfaces, and each one has a method called on()? Roy gave us a satisfactory answer. But as Ewerton than replied, why is it not applied to inheritance as well? I mean, why we cannot just specify which parent class we are referring to, like Roy suggested for interfaces? "infce1.super.on();" --> "toaster.super.on();"
Jakub Góźdź
Level 31 , Katowice, Poland
17 February 2020, 11:00
Nice and simple :)
Ivaylo Trifonov
Level 22 , Madrid, Spain
18 April 2019, 18:45
And what if our class implements 2 interfaces, and each one has a method called on()? Like:
public interface infce1 {
        void on();
    }

    public interface infce2 {
        void on();
    }

    public static class Test implements infce1, infce2 {
        @Override
        public void on() {
            System.out.println("???");
        }
    }
Roy
Level 22 , Bangkok, Thailand
26 April 2019, 00:10
Great question! a quick search gave me this answer; You cannot implement multiple interfaces having same signature of Java 8 default methods (without overriding explicitly in child class) So you need to explicitly override it which will look like this in your code example;
public interface infce1 {
        void on();
    }
    public interface infce2 {
        void on();
    }
    public static class Test implements infce1, infce2 {
        @Override
        public void on() {
            infce1.super.on();//e.g. for interface1
        }
    }
Ewerton Backend Developer
30 June 2019, 15:48
So why didn't they do that with inheritance too( toaster.super.on(); )?
Henrique
Level 41 , São Paulo, Brazil
28 May 2020, 14:34
Boa pergunta!
Yoosen
Level 20 , China
15 August 2020, 01:50
Test.on() belongs to both. If you think it's interface1, it's interface1. If you think it's interface2, it's interface2. Actually, the interface has no concrete implementation method, so there is no conflict. In your case, Method on is not implemented in interface1 or interface2, you should implement this abstract method on() in class Test.
Gellert Varga
Level 23 , Szekesfehervar, Hungary
26 February 2021, 10:11
To Roy, 26 April 2019.
@Override
public void on () {
    infce1.super.on (); // e.g. for interface1
}
You need to write this way only if the on() methods are default in both interfaces! Two inherited methods with the same name only conflict if they both have implementations in the parent interfaces. In this case you need to use super keyword and to point to one of the interfaces. But if one or both of them is not default in the interfaces, then see Yoosen’s comment, 15 August 2020.
// Java Poser
Level 18 , Cincinnati, United States
8 April 2019, 17:38
please no more calendar tasks lmao jk!
Darko Jakimovski
Level 18 , Kriva Palanka, Macedonia, The Former Yugoslav Republic of
27 April 2019, 09:38
Despise that calendar crap myself :D
Henk
Level 19 , Pretoria, South-Africa
11 May 2019, 06:53
Lol! (about Calendar....) agree...
Henk
Level 19 , Pretoria, South-Africa
11 May 2019, 06:53
lol
Berkson
Level 17 , Fortaleza, Brazil
15 June 2019, 14:51
use java datetime api. It´s much more simple. o_o
Thomas Sixberry
Level 16 , Rochester Hills, United States
8 February 2020, 21:18
@Berkson - We're oftentimes forced to do things that no programmer would ever do.