The interface
and abstract class
reference types in Java are used to create abstractions.
Both interface
and abstract class
can’t be instantiated directly. They need to be implemented or extended by other classes.
But these two reference types have many differences that change the way your abstractions work.
One obvious difference is that an abstract class
is a class. A Java class
can only extend one class, but it can implement many interfaces.
Below are some notable differences between Java interface
and abstract class
reference types:
Access modifier for members
An abstract class
can have members with access modifiers (such as private
, protected
, and public
) while interface
members are all public
:
abstract class Individual {
protected String tribe = "Hominini";
private String species = "Homo Sapiens";
public String name = "Nathan";
}
interface Human {
protected String tribe = "Hominini";
// ERROR: protected modifier not allowed
private String species = "Homo Sapiens";
// ERROR: private modifier not allowed
public String name = "Nathan";
// WARNING: public modifier is redundant
}
The protected
and private
access modifiers are not allowed in an interface
.
The public
modifier is redundant because all variable members of an interface
are public by default.
Non-access modifier for members
By default, an interface
members are both static
and final
.
On the other hand, an abstract class
members can be final
, static
, or neither.
Consider the interface
code example below:
interface Human {
String name = "Nathan";
}
public class Main {
public static void main(String[] args) {
System.out.println(Human.name); // Nathan
Human.name = "Jack" // ERROR
}
}
An interface
members can be called directly because they are static
by default.
In an abstract class
, you need to declare the members as static
to access them directly:
abstract class Individual {
String first_name = "Nathan";
static String last_name = "Sebhastian";
}
public class Main {
public static void main(String[] args) {
System.out.println(Individual.first_name); // ERROR
System.out.println(Individual.last_name); // OK
Individual.first_name = "Smith"; // ERROR
Individual.last_name = "Smith"; // OK
}
}
You can also add the final
modifier to make the members value immutable:
abstract class Individual {
// this is the default in interface:
final static String last_name = "Sebhastian";
}
Because abstract class
variables are not final by default, you can declare variables without initializing them as follows:
abstract class Individual {
String first_name;
String last_name;
}
And that’s how the interface
and abstract class
differ in terms of non-access modifiers.
Methods modifier in the reference types
By default, an interface
can only have abstract methods. Declaring a method with implementation will result in a compile-time error:
interface Human {
void greetings() {
System.out.println("Hello!");
}
// ERROR: abstract methods cannot have a body
void call(); // Correct abstract method
}
Since Java 8, the interface
type has been improved so it can also have default
and static
methods.
When you want to provide a default implementation of interface
methods, add the default
modifier as follows:
interface Human {
default void greetings() {
System.out.println("Hello!");
}
// You can also declare a static method:
static void call() {
System.out.println("Hi!");
}
}
In an abstract class
, you can declare both regular and abstract methods as shown below:
abstract class Individual {
void greetings() {
System.out.println("Hello!");
}
abstract void call();
}
Note that you need to add the abstract
modifier when declaring an abstract method in an abstract class
.
Inheritance rule
The interface
and abstract class
have no special inheritance rule.
You can extend a single class and implement multiple interfaces to an abstract class
when you need to:
class A {}
class B {}
interface ZX {}
interface ZY {}
abstract class C extends A, B {}
// ERROR: only one class allowed
abstract class C extends A implements ZX, ZY {}
// OK
On the other hand, an interface
can only extend another interface:
class A {}
interface ZX {}
interface ZY {}
interface Test implements ZX {}
// ERROR: implements not allowed
interface Test extends A {}
// ERROR: interface expected, class A received
interface Test extends ZX, ZY {}
// OK
And those are the notable differences between an interface
and an abstract class
in Java.
When to use interface or abstract class?
The key point to remember is that an interface
is used to achieve complete abstraction, while an abstract class
is used to achieve partial abstraction.
An interface
is used to provide capabilities that an implementing class
will provide.
For example, the Animal
interface promises that the implementing object can walk:
interface Animal {
void walk();
}
But the implementation of the walk
method is left to the object that implements it.
A Dog
class will walk with four legs, while a Kangaroo
class walk with two legs:
class Dog implements Animal {
@Override
public void walk() {
System.out.println("4 legs");
}
}
class Kangaroo implements Animal {
@Override
public void walk() {
System.out.println("2 legs");
}
}
Although now you can have default
and static
methods, the rule remains the same: An interface
defines what an object can do.
On the other hand, an abstract class
is more interested in what an object is.
When using an abstract class
you are giving common characteristics between the implementing objects:
abstract class Person {
String first_name;
String last_name;
int lungs = 2;
void breathe() {
System.out.println("Breathe in.. breathe out");
}
}
A person’s first_name
and last_name
are commonly given when the person is born, so they are declared, but not initialized.
You can’t do the same with an interface
because any variable declared in an interface
is final
.
To sum it up, an interface
is used to provide promises of what an object can do and have.
Meanwhile, an abstract class
provides the shared things that an object can do and have.
I hope this tutorial has helped you to understand the differences between an interface
and an abstract class
. 👍