DEV Community

Cover image for Interfaces vs. Abstract Classes
Paul Ngugi
Paul Ngugi

Posted on

Interfaces vs. Abstract Classes

A class can implement multiple interfaces, but it can only extend one superclass. An interface can be used more or less the same way as an abstract class, but defining an interface is different from defining an abstract class. Table below summarizes the differences.

Image description

Java allows only single inheritance for class extension but allows multiple extensions for interfaces. For example,

public class NewClass extends BaseClass
implements Interface1, ..., InterfaceN {
...
}

An interface can inherit other interfaces using the extends keyword. Such an interface is called a subinterface. For example, NewInterface in the following code is a subinterface of Interface1, . . . , and InterfaceN.

public interface NewInterface extends Interface1, ... , InterfaceN {
// constants and abstract methods
}

A class implementing NewInterface must implement the abstract methods defined in NewInterface, Interface1, . . . , and InterfaceN. An interface can extend other interfaces but not classes. A class can extend its superclass and implement multiple interfaces.

All classes share a single root, the Object class, but there is no single root for interfaces. Like a class, an interface also defines a type. A variable of an interface type can reference any instance of the class that implements the interface. If a class implements an interface, the interface is like a superclass for the class. You can use an interface as a data type and cast a variable of an interface type to its subclass, and vice versa. For example, suppose that c is an instance of Class2 in Figure below. c is also an instance of Object, Class1, Interface1, Interface1_1, Interface1_2, Interface2_1, and Interface2_2.

Image description

Class names are nouns. Interface names may be adjectives or nouns. Abstract classes and interfaces can both be used to specify common behavior of objects. How do you decide whether to use an interface or a class? In general, a strong is-a relationship that clearly describes a parent-child relationship should be modeled using classes. For example, Gregorian calendar is a calendar, so the relationship between the class java.util.GregorianCalendar and java.util.Calendar is modeled using class inheritance. A weak is-a relationship, also known as an is-kind-of relationship, indicates that an object possesses a certain property. A weak is-a relationship can be modeled using interfaces. For example, all strings are comparable, so the String class implements the Comparable interface.

In general, interfaces are preferred over abstract classes because an interface can define a common supertype for unrelated classes. Interfaces are more flexible than classes. Consider the Animal class. Suppose the howToEat method is defined in the Animal class, as follows:

abstract class Animal {
public abstract String howToEat();
}

Two subclasses of Animal are defined as follows:

class Chicken extends Animal {
@Override
public String howToEat() {
return "Fry it";
}
}

class Duck extends Animal {
@Override
public String howToEat() {
return "Roast it";
}
}

Given this inheritance hierarchy, polymorphism enables you to hold a reference to a Chicken object or a Duck object in a variable of type Animal, as in the following code:

public static void main(String[] args) {
Animal animal = new Chicken();
eat(animal);
animal = new Duck();
eat(animal);
}

public static void eat(Animal animal) {
animal.howToEat();
}

The JVM dynamically decides which howToEat method to invoke based on the actual object that invokes the method.

You can define a subclass of Animal. However, there is a restriction: The subclass must be for another animal (e.g., Turkey).

Interfaces don’t have this restriction. Interfaces give you more flexibility than classes, because you don’t have to make everything fit into one type of class. You may define the howToEat() method in an interface and let it serve as a common supertype for other classes.

For example,

public static void main(String[] args) {
Edible stuff = new Chicken();
eat(stuff);
stuff = new Duck();
eat(stuff);
stuff = new Broccoli();
eat(stuff);
}

public static void eat(Edible stuff) {
stuff.howToEat();
}

interface Edible {
public String howToEat();
}

class Chicken implements Edible {
@Override
public String howToEat() {
return "Fry it";
}
}

class Duck implements Edible {
@Override
public String howToEat() {
return "Roast it";
}
}

class Broccoli implements Edible {
@Override
public String howToEat() {
return "Stir-fry it";
}
}

To define a class that represents edible objects, simply let the class implement the Edible interface. The class is now a subtype of the Edible type, and any Edible object can be passed to invoke the howToEat method.

Top comments (1)

Collapse
 
blackr1234 profile image
blackr1234

Interfaces now have default methods.