1. Overview

Java includes several non-access modifiers that play a crucial role in defining the behavior of classes and members. These modifiers enhance the functionality and characteristics of elements within the Java programming language. Among these non-access modifiers are abstract, final, native, static, synchronized, transient, and volatile.

It's worth noting that the modifier strictfp was part of the list, but it has become obsolete and is no longer a used reserved word in Java.

Abstract Non-Access Modifier

The abstract modifier is one of the non-access modifiers in Java. When applied to a class, method, or interface, it indicates that the element does not have a complete implementation. Abstract classes and methods serve as templates that must be extended or implemented by subclasses. Abstract methods declare the method signature but lack a body, leaving the implementation to the subclasses.

This modifier allows for the creation of abstract classes that can't be instantiated on their own but can be extended by concrete subclasses, providing a way to achieve abstraction and define common structure across related classes.

Here's a simple example of an abstract class:

abstract class Shape {
  // Abstract method without implementation
  public abstract void draw();
}

In this example, the Shape class is marked as abstract, and it declares an abstract method draw(). Any concrete subclass of Shape must provide an implementation for the draw() method.

It's important to note that abstract methods can only exist in abstract classes or interfaces, and abstract classes cannot be instantiated directly.

Understanding the proper use of the abstract modifier is crucial for designing effective and extensible Java applications.

2. Abstract Modifier

The term "abstract" signifies something not entirely clear or incomplete. When we embark on developing our programs, there are instances where we encounter situations demanding partial code implementation. In certain scenarios, we may find ourselves unable to confirm the entirety of the implementation at that particular stage. This is precisely where the concept of the abstract modifier comes into play. To delve deeper, let's explore the two fundamental aspects of abstraction in Java: abstract methods and abstract classes.

Abstract Method

An abstract method is a method declared without a concrete implementation in the body. It serves as a blueprint or placeholder for methods that must be defined in any concrete (non-abstract) subclass. The declaration of an abstract method includes only the method signature, leaving the actual implementation to its subclasses.

Abstract Class

An abstract class is a class that cannot be instantiated on its own but can be subclassed by other classes. It may contain both abstract and non-abstract methods. Abstract classes provide a way to achieve abstraction by allowing the definition of methods without providing a complete implementation. Concrete subclasses must extend abstract classes and provide implementations for any abstract methods.

3. Abstract Method

What are Abstract Methods?

Abstract methods are a unique breed in programming that defy the conventional need for immediate implementation. These methods exist purely in declaration, lacking a body or concrete implementation. Key properties of an abstract method include:

  • Declared using the "abstract" keyword in Java.
  • The abstract keyword precedes the method name in the declaration.
  • No body exists within an abstract method, only the method signature is present.
  • An abstract method in Java is denoted by a semicolon (;) at the end.

3.1 Example: Declaring an Abstract Method

Let's consider the creation of a class called Vehicle. Within this class, we need a method, getNumberOfWheels, capable of calculating the number of wheels. Initially, we might write the code as follows:

public class Vehicle {
    public int getNumberOfWheels() {
        /**/
    }
}

However, our intent is for the getNumberOfWheels method to be abstract, as we don't yet know the type of vehicle. It could be a lorry, motorcycle, or tractor. Thus, we want the method to remain incomplete. The revised code is as follows:

public class Vehicle {
    public abstract int getNumberOfWheels();
}

Observe the distinction: the presence of curly braces implies full implementation, while termination with a semicolon signifies a declaration.

3.2 Further Understanding of Abstract Methods

Let's reinforce our understanding with a question:

Based on the statements below, which is a valid statement for an abstract method?

A. public abstract void m1() {}
B. public void m1();
C. public abstract void m1();
D. public void m1() {}

Discussion:

  • Statement A: Not a declaration; it's an implementation with curly braces.
  • Statement B: Lacks the "abstract" keyword despite being a declaration.
  • Statement C: Meets all abstract method requirements, featuring "abstract" and ending with a semicolon.
  • Statement D: Not an abstract method; it has curly braces, indicating implementation.

Returning to our code:

public class Vehicle {
    public abstract int getNumberOfWheels();
}

With the information at hand, the implementation responsibility falls on the child class, a topic we'll explore in the next section.

4. Abstract Class

Understanding Abstractness

Now that we've delved into the concept of abstract, signifying partial implementation or incompleteness, let's explore the realm of abstract classes. An abstract class is, in essence, a partially implemented class, representing an incomplete structure. This incompleteness may arise due to the presence of abstract methods within the class.

There are two scenarios that prompt the declaration of a class as abstract. Firstly, when there's a declaration of an abstract method in the class. Secondly, when, upon evaluating the code, we sense that certain implementations within the class remain incomplete. In both situations, declaring a class as an abstract class is warranted. Let's illuminate this with an example.

4.1 Example: Does Every Abstract Class Have an Abstract Method?

Consider two classes: Attendance and Student. The Attendance class encompasses an abstract method named getTotalAttendance. In the Student class, we attempt to create an object of Attendance and observe the result. Let's see the code:

// Student.java
class Attendance {
  public abstract int getTotalAttendance();
}

class Student {
  public static void main(String[] args) {
    Attendance a = new Attendance();
    a.getTotalAttendance();
  }
}

Upon compiling this code, we encounter an error. The attempt to instantiate an object for an abstract class is the main cause of this error. Even if we modify the code and make Attendance explicitly abstract, the error persists.

// Student.java
abstract class Attendance {
  public abstract int getTotalAttendance();
}

class Student {
  public static void main(String[] args) {
    Attendance a = new Attendance();
    a.getTotalAttendance();
  }
}

Attempting instantiation is futile as the abstract class remains incomplete, and thus, instantiation is not allowed. In essence, a class not explicitly declared as abstract but containing an abstract method should be treated as abstract since instantiation is prohibited. Therefore, for any class harboring an abstract method, the class should be declared as abstract.

4.2 Example: Does Every Abstract Class Have an Abstract Method?

Let's explore another example in a file named A.java. In this case, there exists an abstract class A with the main method stated within it. Attempting to instantiate an object from A inside the main method results in an error. Let's take a look at the code:

// A.java
  abstract class A {
    public static void main(String[] args) {
      A a = new A();
    }
  }

Compiling this code yields an error since object creation for an abstract class is not permissible. Let's rectify this by removing the abstract keyword:

// A.java
  class A {
    public static void main(String[] args) {
      A a = new A();
    }
  }

Upon compilation, the absence of an error indicates that the code is functional. In conclusion, it's not mandatory for an abstract class to have an abstract method, as abstract classes can contain zero abstract methods. A class can be declared as abstract if deemed incomplete to prevent object creation. While abstract classes can contain zero abstract methods, the presence of an abstract method necessitates the class's declaration as abstract.

5. Abstract Method and Abstract Class

In this section, we'll delve into the distinctions between an abstract class and an abstract method, elucidating the concepts through illustrative examples.

5.1 Example: Implementing Abstract Methods

Consider the file SubTest.java where an abstract class Test and its child class SubTest are defined.

// SubTest.java
abstract class Test{
	public abstract void m1();
	public abstract void m2();
}
public class SubTest extends Test{
	public void m1(){}
}

Attempting to implement the abstract method m1() in SubTest introduces a dilemma. According to the rule, all methods from the parent class must be implemented in the child class. There are two solutions: either implement m2() in SubTest, or declare SubTest as an abstract class. Let's explore both options:

Solution 1

First, is by providing implementation for m2(). Therefore, the code should be changed as follow:

//SubTest.java
abstract class Test{
	public abstract void m1();
	public abstract void m2();
}
public class SubTest extends Test{
	public void m1(){}
	public void m2(){}
}

Solution 2

In the second approach, the responsibility to provide implementation shifts to the next level child class. However, both Test and SubTest remain abstract, requiring the creation of a concrete child class like SubSubTest to finalize the implementation.

//SubSubTest.java
abstract class Test{
	public abstract void m1();
	public abstract void m2();
}
public class SubTest extends Test{
	public void m1(){}
}
public class SubSubTest extends SubTest{
	public void m2(){}
}

5.2 Example: Creating Objects from Abstract Methods and Classes

Now, let's explore an example involving an abstract class Vehicle and its child classes Bus and Auto. The abstract method getNoOfWheels() is implemented in the child classes. Observe the following scenarios:

// Abstract class Vehicle and its child classes
abstract class Vehicle {
  public abstract int getNoOfWheels();
}

class Bus extends Vehicle {
  public int getNoOfWheels() {
    return 6;
  }
}

class Auto extends Vehicle {
  public int getNoOfWheels() {
    return 3;
  }
}

// Case 1: Attempting to create an object for the abstract class
public class Test {
  public static void main(String[] args) {
    Vehicle v = new Vehicle();
  }
}

In Case 1, an attempt to create an object for the abstract class Vehicle results in an error since instantiation of abstract classes is not allowed.

// Case 2: Creating objects for the concrete child classes
public class Test {
  public static void main(String[] args) {
    Bus b = new Bus();
    Auto a = new Auto();
    System.out.println(b.getNoOfWheels());
    System.out.println(a.getNoOfWheels());
  }
}

In Case 2, objects for concrete child classes Bus and Auto can be created successfully since both are not abstract. The advantage of having the abstract method in this scenario lies in enforcing every child class to provide implementation for getNoOfWheels().

End Of Article

End Of Article