What Are the Differences Between Abstract Classes and Interfaces in Java 8

What are the differences between abstract classes and interfaces in Java 8?

Interfaces cannot have state associated with them.

Abstract classes can have state associated with them.

Furthermore, default methods in interfaces need not be implemented. So in this way, it will not break already existing code, as while the interface does receive an update, the implementing class does not need to implement it.

As a result you may get suboptimal code, but if you want to have more optimal code, then your job is to override the default implementation.

And lastly, in case a diamond problem occurs, then the compiler will warn you, and you will need to choose which interface you want to implement.

To show more about the diamond problem, consider the following code:

interface A {
void method();
}

interface B extends A {
@Override
default void method() {
System.out.println("B");
}
}

interface C extends A {
@Override
default void method() {
System.out.println("C");
}
}

interface D extends B, C {

}

Here I get the compiler error on interface D extends B, C, that:

interface D inherits unrelated defaults for method() form types B and C

The fix is:

interface D extends B, C {
@Override
default void method() {
B.super.method();
}
}

In case I wanted to inherit the method() from B.

The same holds for if D were a class.

To show even more about the difference between interfaces and abstract classes in Java 8, consider the following Team:

interface Player {

}

interface Team {
void addPlayer(Player player);
}

You can in theory provide a default implementation of addPlayer such that you can add players to for example a list of players.

But wait...?

How do I store the list of players?

The answer is that you cannot do that in an interface, even if you have default implementations available.

What is the difference between abstract classes and interfaces in Java 8 and beyond?

The main difference between an abstract class and interface in Java 8 is the fact that an abstract class is a class and an interface is an interface.

A class can have a state which can be modified by non-abstract methods but an interface cannot have the state because they can't have instance variables.

The second difference is that an interface cannot have a constructor even in Java 8 but you may remember that abstract class always has a constructor in Java.

In reality, default or defender methods are introduced to maintain backward compatibility and same time making Collection API more suitable to be used inside key Java 8 features like lambda expressions.

Without adding default methods, it wasn't possible to declare any new method on existing interface in Java without breaking all classes which implement it, but because of default method, you can now better evolve your API.

They defend your code against implementing new methods hence they are also called defender methods.

What is the difference between an interface and abstract class?

Interfaces

An interface is a contract: The person writing the interface says, "hey, I accept things looking that way", and the person using the interface says "OK, the class I write looks that way".

An interface is an empty shell. There are only the signatures of the methods, which implies that the methods do not have a body. The interface can't do anything. It's just a pattern.

For example (pseudo code):

// I say all motor vehicles should look like this:
interface MotorVehicle
{
void run();

int getFuel();
}

// My team mate complies and writes vehicle looking that way
class Car implements MotorVehicle
{

int fuel;

void run()
{
print("Wrroooooooom");
}

int getFuel()
{
return this.fuel;
}
}

Implementing an interface consumes very little CPU, because it's not a class, just a bunch of names, and therefore there isn't any expensive look-up to do. It's great when it matters, such as in embedded devices.


Abstract classes

Abstract classes, unlike interfaces, are classes. They are more expensive to use, because there is a look-up to do when you inherit from them.

Abstract classes look a lot like interfaces, but they have something more: You can define a behavior for them. It's more about a person saying, "these classes should look like that, and they have that in common, so fill in the blanks!".

For example:

// I say all motor vehicles should look like this:
abstract class MotorVehicle
{

int fuel;

// They ALL have fuel, so lets implement this for everybody.
int getFuel()
{
return this.fuel;
}

// That can be very different, force them to provide their
// own implementation.
abstract void run();
}

// My teammate complies and writes vehicle looking that way
class Car extends MotorVehicle
{
void run()
{
print("Wrroooooooom");
}
}

Implementation

While abstract classes and interfaces are supposed to be different concepts, the implementations make that statement sometimes untrue. Sometimes, they are not even what you think they are.

In Java, this rule is strongly enforced, while in PHP, interfaces are abstract classes with no method declared.

In Python, abstract classes are more a programming trick you can get from the ABC module and is actually using metaclasses, and therefore classes. And interfaces are more related to duck typing in this language and it's a mix between conventions and special methods that call descriptors (the __method__ methods).

As usual with programming, there is theory, practice, and practice in another language :-)

When to use: Java 8+ interface default method, vs. abstract method

There's a lot more to abstract classes than default method implementations (such as private state), but as of Java 8, whenever you have the choice of either, you should go with the defender (aka. default) method in the interface.

The constraint on the default method is that it can be implemented only in the terms of calls to other interface methods, with no reference to a particular implementation's state. So the main use case is higher-level and convenience methods.

The good thing about this new feature is that, where before you were forced to use an abstract class for the convenience methods, thus constraining the implementor to single inheritance, now you can have a really clean design with just the interface and a minimum of implementation effort forced on the programmer.

The original motivation to introduce default methods to Java 8 was the desire to extend the Collections Framework interfaces with lambda-oriented methods without breaking any existing implementations. Although this is more relevant to the authors of public libraries, you may find the same feature useful in your project as well. You've got one centralized place where to add new convenience and you don't have to rely on how the rest of the type hierarchy looks.

When to use interface vs abstract class after Java 8

default methods on interface

Apparently you are referring to the feature of “default methods” implementing behavior in an interface.

You should understand that the feature was added as a way around this dilemma: How to retroactively add features leveraging streams and lambda on existing interfaces without breaking existing classes that implement those interfaces?

Many new methods were added to those interfaces such as in the Java Collections Framework. Adding methods to an existing interface would automatically break all classes implementing the interface that are lacking the newly-required methods. Being able to provide a fallback, to give an implementation where one is now required but not yet existing, would resolve the dilemma. Thus « default methods » were born.

To quote from the Oracle tutorial linked above:

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.

To quote this Answer by Brian Goetz, Java Language Architect at Oracle:

The proximate reason for adding default methods to interfaces was to support interface evolution

So this feature of adding default behavior to an interface was not meant to be a new mainstream feature in and of itself. The intent of default was not to replace abstract.

Indeed, some experienced Java experts have recommended against making a habit of writing default methods on an interface. They recommend pretty much ignoring that feature of the Java language. Continue to think of interfaces as simply defining a contract, and abstract classes as providing partial implementations meant to be completed in a subclass.

You are certainly free to write your own default methods on your interfaces. And certainly you should do so if you are in a similar situation of having published an interface that others may have implemented, and now you want to add methods. But unnecessarily adding default methods is likely to confuse other programmers who expect partial implementations on an abstract class rather than an interface.

Four situations calling for default method on an interface

In that same post linked above, Brian Goetz suggests three other cases beyond interface evolution where default methods on an interface may be appropriate. Here is a quick mention; see his post for details.

  • Optional methods - The default method throws an UnsupportedOperationException because we expect implementations of this interface to more often not want to implement this method.
  • Convenience methods
  • Combinators

Start with interface, move to abstract class for shared code

As for choosing between an interface and abstract class:

  • Generally start with an interface. Or several interfaces if you want various implementing classes to mix various contracts (see mixin).
    • Think twice before adding a default method. Consider if your situation meets one of the four cases recommended by Brian Goetz as discussed above.
  • If you come to realize that you have duplicated code across multiple classes, then consider centralizing that shared code to an abstract class to be used across subclasses.
    • Alternatively, use composition rather than inheritance (discussed below).

For example, you might have a class for domestic ShippingLabelUS as well as ShippingLabelCanada and ShippingLabelOverseas. All three need to convert between imperial pounds and metric kilograms. You find yourself copying that code between the classes. At this point you might consider having all three classes extend from abstract class ShippingLabel where a single copy of the weight conversion methods live.

While designing your API keep in mind that Java, like most OOP languages, has single-inheritance. So your subclasses are limited to extending only one class. To be a bit more specific about the single-versus-multiple inheritance, I will quote Brian Goetz from this PDF of a slide deck:

[regarding default methods on an interface]

Wait,is this multiple inheritance in Java?

• Java always had multiple inheritance of types

• This adds multiple inheritance of behavior

• But not of state, where most of the trouble comes from

Composition over inheritance

An alternative to using an abstract class for shared behavior is creating a separate class for specific behavior, then adding an object of that separate class to be kept as a member field on the larger class. Wise programmers often share this pearl of wisdom: Prefer composition over inheritance.

Regarding the shipping label example above, you could create a WeightConverter class, an object of which would be a member of each of the three label classes. In this arrangement, no need for the abstract class.

Fundamental difference between interface and abstract class in Java 8

Interfaces still can't have any state. Interfaces still can't have any final method, which means that any implementation can override all its default methods. And interfaces still can't have any constructor.

You can still implement multiple interfaces, even if they have default methods with the same signature. You can't extend multiple classes (abstract or not).

Java 8 -- interfaces with default methods vs abstract classes

Here are some reasons to choose an abstract class over an interface. The ones you list - private fields, etc., are some of the major ones. These are a few more subtle ones

  • Type clarity. You can only extend one class. This makes it clearer what your object is an how to use it.
  • The diamond problem. You have to implement all of the default methods in an interface to help avoid the diamond problem. If the interface is Collections, this can be a huge pain since there are a billion of them. With an abstract class, you only overwrite what you need to
  • In Java 8, there are lambda expressions, and the old routine of passing around an interface with a method to implement has been usurped. Still, when you see an interface with a default method, this can interpreted in ways you might not intend

Here's what Oracle has to say on the subject:

Which should you use, abstract classes or interfaces?
Consider using abstract classes if any of these statements apply to
your situation:

  • You want to share code among several closely related classes.
  • You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than
    public (such as protected and private).
  • You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the
    object to which they belong.

In this article, Orace defends the distinction between the two type systems
https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

EDIT To clarify the "diamond problem" bullet
The problem is described here (and many other places)
http://www.lambdafaq.org/what-about-the-diamond-problem/

The problem occurs when you inherit from two places that declare the same method, and you have to pick one when resolving a function call. This was never an issue in Java 7-, since you could only extend one class and interfaces had no methods.

The resolution tactic now is a little complicated, but here is a good description of it:
(from http://blog.loxal.net/2013/05/java-8-default-interface.html)

To address the diamond problem there is a precedence in which order an
implementation is used: only if the class implements all default /
optional methods of its interfaces, the code can be compiled and the
implementations of this class are used. Otherwise the compiler tries
to patch the missing implementation(s) with interface's default
implementation. And if there are multiple default implementations of a
method, then the diamond problem occurs and the compiler rejects the
compilation. Also if the class implements an interface's default
method, the implementation of the class will be used instead of
interfaces's default implementation.

If you stick to abstract classes, you will never run into this problem. However, if your object is required to implement two interfaces (because it needs to be added to lists that are expecting those types, e.g.), and those interfaces have conflicting method signatures, you will wind up having to redefine a whole bunch of methods even if that means you're just making super calls, which sort of defeats the point of inheritance-based dynamic dispatch. It isn't a deal-breaker, but something to consider when structuring a complex Java project

Java 8 Interface vs Abstract Class

That sentence means that a default method is implemented inside an interface, so it doesn't have any access to a real state of an object but just to what the interface itself exposes, since an interface can't declare instance variables.

For example:

abstract class Foo {
int result;
int getResult() { return result; }
}

This can't be done in an interface because you can't have any member variable. The only thing you can do is to combine multiple interface methods, which is what it is specified as convenience / higher-level methods, eg:

interface Foo {
void preProcess();
void process();
void postProcess();

default void processAll() {
preProcess();
process();
postProcess();
}
}

How should I have explained the difference between an Interface and an Abstract class?

I will give you an example first:

public interface LoginAuth{
public String encryptPassword(String pass);
public void checkDBforUser();
}

Suppose you have 3 databases in your application. Then each and every implementation for that database needs to define the above 2 methods:

public class DBMySQL implements LoginAuth{
// Needs to implement both methods
}
public class DBOracle implements LoginAuth{
// Needs to implement both methods
}
public class DBAbc implements LoginAuth{
// Needs to implement both methods
}

But what if encryptPassword() is not database dependent, and it's the same for each class? Then the above would not be a good approach.

Instead, consider this approach:

public abstract class LoginAuth{
public String encryptPassword(String pass){
// Implement the same default behavior here
// that is shared by all subclasses.
}

// Each subclass needs to provide their own implementation of this only:
public abstract void checkDBforUser();
}

Now in each child class, we only need to implement one method - the method that is database dependent.



Related Topics



Leave a reply



Submit