Understanding Abstractions in Java

Photo by Glenn Carstens-Peters on Unsplash

What is Abstraction?

Abstraction is a fundamental concept in Object-Oriented Programming (OOP) that involves concealing the intricate implementation details and presenting only the essential information to users for interaction. This approach enables users to focus solely on what the code accomplishes rather than how it accomplishes it behind the scenes.

For instance, consider a remote control. It offers a user-friendly interface allowing users to perform actions like turning the television on/off, adjusting the volume, or changing channels. However, users remain unaware of the detailed implementation behind these functionalities.

Abstraction in Java

In Java, abstraction finds expression through two primary mechanisms: abstract classes and interfaces.

Abstract classes

The abstract keyword, among Java's non-access modifiers, serves to define abstract classes and methods within them.

Returning to our remote control analogy, abstract classes enable us to capture common functionalities shared among various types of remote controls, such as turning devices on/off. Meanwhile, specific functionalities like changing channels may differ in implementation.

abstract class RemoteControl {
// Abstract method to change the channel
public abstract void changeChannel(int channel);

// Concrete method to turn the device on
public void turnOn() {
System.out.println("Turning on the device");
}

// Concrete method to turn the device off
public void turnOff() {
System.out.println("Turning off the device");
}
}

// Subclass for TVRemoteControl
class TVRemoteControl extends RemoteControl {
public void changeChannel(int channel) {
System.out.println("Changing TV channel to " + channel);
}
}

// Subclass for DVDRemoteControl
class DVDRemoteControl extends RemoteControl {
public void changeChannel(int channel) {
// DVD players don't have channels, so this method does nothing
}
}

Observing the code snippet above, several key points emerge:

  1. Abstract methods lack implementation details.
  2. Other methods within the abstract class possess concrete implementations and, thus can be shared with inheriting subclasses (e.g., TVRemoteControl, DVDRemoteControl).
  3. The extends keyword facilitates the inheritance of properties from the abstract class by subclasses.
  4. Abstract classes cannot be instantiated directly; instead, they are inherited by relevant subclasses.

Interfaces

In Java, an interface acts as a reference type, solely permitting constants, method signatures, default methods, static methods, and nested types.

// Interface representing a remote control
interface RemoteControl {
// Method to change the channel
void changeChannel(int channel);

// Method to adjust the volume
void adjustVolume(int volume);
}

Key considerations regarding interfaces include:

  1. Declaration via the interface keyword.
  2. Methods lacking a body, akin to abstract methods in abstract classes.
  3. Although not shown in the code, interfaces can include constants, implicitly public, static, and final.

Subclasses can then implement the declared interface using the implements keyword.

// Class representing a TV remote control implementing the RemoteControl interface
class TVRemoteControl implements RemoteControl {
public void changeChannel(int channel) {
System.out.println("Changing TV channel to " + channel);
}

public void adjustVolume(int volume) {
System.out.println("Adjusting TV volume to " + volume);
}
}

// Class representing a DVD remote control implementing the RemoteControl interface
class DVDRemoteControl implements RemoteControl {
public void changeChannel(int channel) {
// DVD players don't have channels, so this method does nothing
}

public void adjustVolume(int volume) {
System.out.println("Adjusting DVD volume to " + volume);
}
}

With the introduction of Java 8, interfaces gained support for default and static methods, enhancing their utility. Default methods allow method declarations with implementations within the interface itself, which can either be utilized by subclasses or overridden using the @Override keyword. Similarly, static methods in interfaces operate akin to those in regular classes, enabling method invocation without object instantiation.

Choosing Between Abstract Classes and Interfaces

Both abstract classes and interfaces share the goal of concealing implementation details from users. However, they exhibit differences that make them suitable for distinct use cases.

For instance, they differ in terms of access modifiers. While interface methods are inherently public and abstract, and interface fields are implicitly public, static, and final, abstract classes offer flexibility in access modifiers for their fields and methods.

Use abstract classes when:

  1. Providing a common base implementation for a group of related classes.
  2. Sharing code among multiple closely related classes.
  3. Declaring non-static or non-final fields.
  4. Providing default implementations for some methods while leaving others for subclass implementation.
  5. Utilizing constructors or needing to define constructors with different parameters in subclasses.

Use interfaces when:

  1. Defining a contract specifying the behavior expected from implementing classes.
  2. Achieving multiple inheritance of type, as a class can implement multiple interfaces but extend only one class.
  3. Ensuring loose coupling between components by programming to interfaces rather than concrete implementations.
  4. Supporting functionality across unrelated classes (e.g., Comparable).
  5. Defining a mixin or marker interface without adding method implementations (e.g., Serializable).

Conclusion

In summary, interfaces offer greater flexibility and promote better design practices like loose coupling and polymorphism. They are ideal for defining contracts and achieving multiple inheritance of type. However, if common implementation code needs to be shared among related classes or a base class with default behavior is necessary, abstract classes may be more suitable. In practice, a combination of interfaces and abstract classes is often utilized in Java projects to leverage their respective strengths.

Stackademic 🎓

Thank you for reading until the end. Before you go:


Understanding Abstractions in Java was originally published in Stackademic on Medium, where people are continuing the conversation by highlighting and responding to this story.