Java Abstract Class: In-Depth Tutorial to Using Abstract Class in Java

javaabstractclassAbstract class in Java is a special type of class that contains abstract methods. It’s a very useful concept in Object Oriented Programming in general and Java in particular. An abstract class isn’t very dissimilar to the English word, ‘abstract’, from which it derives its name, as we will learn below.

In this tutorial, we’ll learn the basics of abstract class in Java and how to use it with an in-depth example. Check out this course to learn similar advanced topics in Java.

Understand Abstract Classes in Java

There’s a concept in Object Oriented Programming (OOP) called ‘abstraction’. This method basically enables the programmer to create a class that cannot be instantiated.

If you remember our previous tutorials on Java, you would know that inheritance in OOP is a feature which enables a class to use the members of another class and embellish them with new capabilities. You might also remember that subclasses derive their members from superclasses.

Essentially, an abstract class is just a superclass which enables other classes to inherit from it so that each subclass can share a common design. Programmers like to use abstract classes to reduce dependency on a range of specific subclass types.

Each abstract class contains an abstract method. To declare an abstract method, you can use the following syntax:

                abstract return-type method-name(parameter-list);

If you want to include an abstract method in a class, you have to declare the class as abstract as well. This is how we create abstract classes.

                public abstract class {
                                public abstract return-type method-name(parameter-list);

Completely new to Java programming? Master the basics in this course on Java fundamentals.

An Abstract Class Example

The best way to learn programming, of course, is by actually doing it. To know more about abstract class and how you can use it in a program, let’s consider an example.

Suppose you’ve been hired by the HR department of a local company to create a program that calculates the salaries of different employees. Salaries are calculated on a monthly basis and there are three types of employees at the company. These are:

  1. Employees who are paid a fixed monthly salary.
  2. Employees who are paid hourly. They also get paid an excess amount if they put in more than 168 hours in a month.
  3. Employees who work on commission. They get a percentage of their monthly sales.

We’ll now create separate classes for each of the three employee-types. We’ll name the first one fixedSalary, the second hourlySalary, and the third, commissionPay.

Adding the Abstract Class

Although they may be paid differently, all the three employee types can be grouped together under a larger heading called employees. In other words, these are subclasses of a superclass.

To group these employees together, we’ll create an abstract superclass called Employees. This superclass will house all the properties that will be automatically shared with the three separate subclasses, such as name, social security number, etc.

To see how this works, take a look at the code below:

public abstract class Employees {
                 private String firstName;
                 private String lastName;
                 private String securityNumber;
                 public Employees(String first, String last, String ssn)
                                 firstName = first;
                                 lastName = last;
                                 securityNumber = ssn;
                 } // end constructor
                 public void setFirstName(String first) {
                                 firstName = first;
                 public void setLastName(String last) {
                                 lastName = last;
                 public void setSecurityNumber(String ssn) {                                 
                          securityNumber = ssn
                 public String getFirstName() {
                                 return firstName;
                 public String getLastName() {
                                 return lastName;
                 public String getSecurityNumber() {
                                 return securityNumber;
                 // return String of object
                 public String toString()
                                 return String.format(“%s %s\nsocial security number: %s”, getFirstName(), getLastNam
(), getSecurityNumber());
                                 //The %s is a special formatter that gets the value being held in the
                                 //three methods listed, respectively
                 public abstract double earnings();            //this method will be changed with each subclass

} //end abstract class Employee

Confused? Let’s inspect the code a little closer:

We made the abstract class Employees and have three fields: firstName, lastName and securityNumber. You should know by now that we usually make these fields private or protected. We then make our default constructor Employees. We then have our setters and our getters, and so far we have been looking at things you would mostly be familiar with. You will, however, see two methods that you might not know, and these are the earnings() and toString() methods. If you look, it seems like we shouldn’t care what earnings() does in the class because it will not be invoked. However, the subclasses of Employees will override earnings(), so implementing it is unnecessary. This is why we make this method abstract.

So the next time you want a class to contain a particular method but you want the implementation of that method to be determined by subclasses, you need to make that method abstract. Abstract methods consist of a method signature, but no method body. When declaring a method abstract, the class must also be declared abstract. The abstract method will force subclasses to override it, but if they don’t, then that subclass must be abstract as well and any of their children must override it. Eventually, a descendant class must implement the abstract method or you would have a hierarchy of abstract classes that cannot be instantiated.

As far as the method earnings() is concerned, we’d want to calculate the earnings of an individual based on the type of employee (subclass), so making the method abstract helps a lot.

The method toString()returns a string containing the first name, last name and social security number of the employee. As seen in the comment, the %s is a string formatter that takes the value being held in the variables following the string and places that value there in the string in its stead. You will notice that there are three formatters seen in a string, followed by three variables (methods). The first formatter will be replaced by the value held in the first method variable, the second formatter will be replaced by the value held in the second variable, and so forth.

All this sounded Greek to you? Pick up the basics of Java in this course on Java for beginners!

The fixedSalary Subclass

If you take a look at the code below, you will realize that when naming the class fixedSalary, we used the extends keyword. We can look at it like this: a subclass is an extension of a superclass. The class contains the default constructor that takes a first name, a last name and a social security number as arguments. It contains a setter that assigns an integer to an instance variable, monthSalary. It also contains a getter that returns the monthSalary value and the earnings method which overrides the same method in the superclass and calculates the employee’s earnings under the fixed salary type of payment. If the earnings method is not implemented then the class must be abstract, otherwise a compilation error will occur.

In the setter you will see an if statement in ternary format. The method toString() returns a string including the employee’s type followed by specific information produced by the Employees superclass. This method overrides the same method in Employees.

public class fixedSalary extends Employees {

        private double monthSalary;

        public fixedSalary(String, first, String last, String ssn, double salary) {
                 super(first, last, ssn); // passes to Employee constructor
        } // end default constructor
        public void setMonthSalary(double salary) {
                 monthSalary = salary < 0.0 ? 0.0 :salary;
       public double getMonthSalary() {
                return monthSalary;
       //overrides earnings from Employees class
       public double earnings() {
               return getMonthSalary();
       //return string for object fixedSalary
       public String toString() {
                return String.format ( “Fixed salary employee: %s\n%s: $%,.f”,
                super.toString(), “monthly salary”, getMonthSalary());
} //end class


The hourlySalary Subclass

This class also extends the Employees class and includes the default constructor that takes as arguments a first name, last name, social security number, an hourly wage and the number of hours worked in a specific week. The setters setPay and setHours assign new values to fields pay and hours. setPay ensures that the value in pay is not negative, while setHours ensures that the total number of hours is between 0 and 672 hours, which is the number of hours in a month (yes I know the number of hours in a month varies. I’m working with the assumption that every month has 28 days in them). The earnings method calculates an employee’s salary under this pay scheme. The toString() method calls the same method from the superclass, which enables it to obtain the superclass’s specific information, which in this case is the first and last names, and the social security number.

public class hourlySalary extends Employees {
         private double pay; // pay per hour
         private double hours; //hours worked for the month

         public hourlySalary(String first, String last, String ssn, double hourlyPay, double hoursWorked) {
                   super(first, last ssn);
         } //end default constructor

        public void setHours(double hoursWorked) {
                hours = ((hoursWorked >= 0.0) && (hoursWorked <= 672.0)) ?
                hoursWorked : 0.0;
        public double getPay() {
                 return pay;
       // calculate
       public double earnings() {
                if (getHours() <= 168) // no overtime
                         return getPay() * getHours();
                         return 168 * getPay() + (getHours() – 168) * getPay() * 1.5;
       public String toString() {
               return String.format(“hourly employee: %s\n%s: $%, .2f; %s: %, .2f”, super.toString(), “hourly pay”, getPay(), “hours worked”, getHours());
       } //end method toString
} //end class

The commissionPay Subclass

The final class follows the same format as before. Can you see the code below and figure out what we’re doing – in terms of the previous subclass?

public class commissionPay extends Employees {
        private double monthSales; // sales per month
        private double commRate; // commission percentage

        public commissionPay (String first, String last, String ssn, double sales, double rate) {
                 super(first, last, ssn);
        } //end default constructor

        public void setcommRate(double rate) {
                 commRate = (rate >0.0 && rate< 1.0) ? rate: 0.0;
        public void setmonthSales(double sales) {
                 monthSales = ( sales < 0.0) ? 0.0 : sales;
        public double getcommRate(){
                return commRate;
        public double getmoonthSales() {
                return monthSales;
        public double earnings() {
                 return getcommRate() *getmonthSales();

        //return string
        public String toString() {
                 return String.format(“%s: %s\n%s: $%,.f; %s: %.f”,
                          “commission employee”, super.toString(), “gross sales”, getmonthSales(),
                          “commission rate”, getcommRate());
        } //end method toString
} //end class

Running the Program

Now that we’ve written our entire program, it’s time to run it. We’ve created nearly 200 lines of code so far. We’ve created three subclasses and an abstract class. When we run the program, it will first manipulate the objects made through the three subclasses we created earlier via variables of each object’s own type, then again using an array of Employees variable.

After doing this, the program will, by polymorphism, determine and outputs the type of object in the Employees array. Note the arrays being used in our code plus the elements being called and manipulated. Copy and paste the below code and see what you get. Debugging OOP code can be quite tedious. Error codes don’t often tell the whole story. If you’re having problems, try replacing the formatters with normal concatenation. Also, make sure the names of your classes and objects agree. For example, I kept putting Employee instead of Employees. Errors like this will cause unnecessary compilation problems, and even more problems even if it does compile.

public class PayrollProgramTest {
          public static void main(String[] args) {
                  //create objects for each subclass
                  fixedSalary fixedSalary =
                        new fixedSalary(“Clark”, “Kent”, “555-999-5555”, 15000.00);
                  hourlySalary hourlySalary =
                        new hourlySalary(“Bruce”, “Wayne”, “555-777-1111”, 20.00, 165);
                  commissionPay commissionPay =
                        new commissionPay(“Peter”, “Parker”, “555-111-5555”, 95000, 0.06);
                  //Printing names
                  System.out.printf(“%s\n%s: $%,.f\n\n”,
                         fixedSalary, “earned”, fixedSalary.earnings());
                  System.out.printf(“%s\n%s: $%,.f\n\n”,
                         hourlySalary, “earned”, hourlySalary.earnings());
                  System.out.printf(“%s\n%s: $%,.f\n\n”,
                         commissionPay, “earned”, commissionPay.earnings());

                  // create three-element Employees array
                  Employees [] Employees = new Employees[3];

                  Employees[0] = fixedSalary;
                  Employees[1] = hourlySalary;
                  Employees[2] = commissionPay;

                  // generically process each element in array Employees
                  for (Employees currentEmployees : Employees) {
                           System.out.println(currentEmployees); //invokes toString
                           System.out.printf(“earned $%,.f\n\n”, currentEmployees.earnings());
                  } //end for
       }//end main
}//end class PayrollSystemTest

So there you have it – your complete Java program! Try to run it and see what the output looks like. If you run into any errors, go through the code again and check for typos and misspellings.

If you want to learn more about classes in Java, check out this course to learn Java from scratch!