Abstraction is one of the four fundamental concepts (Encapsulation, Inheritance, Polymorphism, and Abstraction) in Java OOP. Abstraction focuses on hiding complex implementation details, and only showing essential features of an object. Abstraction can be achieved with either abstract classes or interfaces, it is used extensively in Dynamic Method Dispatch (Runtime Polymorphism) that all objects implementing the same interface or inherited from the same abstract class will have the same methods, the method which will be call for a particular object will be determined at runtime.

Abstract class

An abstract class cannot be instantiated on its own and it is meant to be extended. It can have both abstract methods (methods without implementations) and concrete methods (methods with implementations).

abstract class Animal {
    // abstract method (does not have a body)
    abstract void makeSound();
    
    // concrete method
    void sleep() {
        System.out.println("This animal sleeps");
    }
}
 
class Dog extends Animal {
    // providing implementation for the abstract method
    void makeSound() {
        System.out.println("Dog barks");
    }
}
 
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.makeSound(); 
        dog.sleep(); 
    }
}
Dog barks
This animal sleeps

Interface

An interface is a reference type in Java that can contain only abstract methods (until Java 8, which introduced default and static methods) and constants (public static final). It is a way to achieve full abstraction, as it only declares methods that implementing classes must provide. A class can have multiple interfaces, and a interface an inherit from another interface, the class that implements the inherited interface has to provide implementations for methods in the super interface. There are three types of interfaces in Java, the normal interface, functional interface, and the marker interface.

Normal interface

Abstract method

All methods in an interface are abstract and public by default. Private methods are supported in interfaces after Java SE 9, protected methods are not supported in interfaces.

interface Animal {
    // abstract method (implicitly public and abstract)
    void makeSound();
}
 
class Dog implements Animal {
    // providing implementation for the abstract method
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

Default method

Default method is a new language feature introduced in Java SE 8. The default keyword allows methods in a interface to provide implementations.

To call default methods from an interface that an implementing class has overridden, use the super keyword.

interface Animal {    
    // default method
    void makeSound() {
	    System.out.println("Animal sound");
    }
}
 
class Dog implements Animal {
    public void printDogType() {
        System.out.println("I am a dog");
    }
    
    // use <Interface>.super.<Method>(); to specify the specific interface
    // which default implementation you want to invoke
    @Override
	public void makeSound() {
		Animal.super.makeSound();
	}
}
 
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.printDogType(); 
        dog.makeSound(); 
    }
}
I am a dog
Animal sound

Static method

Interfaces can have static method with a body from Java SE 8, these methods belong to the interface itself, not to the instances of the classes that implement the interface.

interface Animal {
    // static method in interface
    static void printType() {
        System.out.println("I am an animal");
    }
    
    // abstract method
    void makeSound();
}
 
class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark");
    }
}
 
public class Main {
    public static void main(String[] args) {
        // invoking the static method in the interface
        Animal.printType();
        
        // creating an instance of Dog and calling the makeSound method
        Dog myDog = new Dog();
        myDog.makeSound();
    }
}
I am an animal
Bark

Functional interface

A functional interface is a special type of interface that has exactly one abstract method, or Single Abstract Method (SAM). The SAM represents the interface’s function. Functional interfaces can be used with lambda expressions, method references, and constructor references. A functional interface can have multiple default methods, static methods. They are often annotated with @FunctionalInterface (optional but recommended).

@FunctionalInterface
public interface Calculator {
	// SAM
	int calculate(int num1, int num2);
}

We can implement this interface with lambda expression.

public static void main(String[] args) {
	Calculator add = (num1, num2) -> num1 + num2;
	System.out.println(add.calculate(2, 4));
}
6

Marker interface

A marker interface is an interface that has no methods or constants. It used to mark or tag a class to allow special behaviour or metadata at runtime.

public interface Serializable {
    // no methods or fields
}

For example, classes that implement Serializable can be serialised, which means their objects’ state can be converted into a byte stream and stored in persistent storage (like hard disks). When objects are destroyed, their state can be preserved and later recreated with the same data by deserialisation. This process allows for data persistence across program runs and even across different environments. By default, Java does not allow objects to perform serialisation, only those implement the Serializable interface have the permission. The Serializable is acting as the marker or tag. There are other marker interfaces in Java such as Cloneable and Remote.


Back to parent page: Java Standard Edition (Java SE) and Java Programming

Web_and_App_DevelopmentProgramming_LanguagesJavaAbstractionInterfaceAbstract_ClassAbstract_MethodFunctional_InterfaceSerialisationMarker_Interface

Reference: