Interfaces in Java always contained
method declaration not their definitions (method body). There was no way of
defining method body / definition in interfaces. This is because historically
Java didn’t allow multiple inheritance of classes. It allowed multiple
inheritance of interfaces as interface were nothing but method declaration.
This solves the problem of ambiguity in multiple inheritance. Since Java 8 it
is now possible to add method bodies in interfaces.
Java 8 has a new feature called
Default Methods. It is now possible to add method bodies into interfaces!
In above Math interface we added a
method multiply with actual method body.
Why we need Default Methods?
Why would one want to add methods
into Interfaces? We’ll it is because interfaces are too tightly coupled with
their implementation classes. i.e. it is not possible to add a method in
interface without breaking the implementor class. Once you add a method in
interface, all its implemented classes must declare method body of this new
method.
Since Java 8,
things started getting ugly. A new feature Lambda was introduce which is cool.
However it is not possible to use this feature in existing Java libraries such
as java.util package. If you add a single method in interface List, it breaks
everything. You need to add its implementation in every class that implements
List interface. Imagine in real world how many custom classes would change.
So for backward compatibility, Java 8
cleverly added Default Methods.
Virtual Extension Methods:
It added a new concept Virtual
extension method, or as they are often called defender methods, can now be
added to interfaces providing a default implementation of the declared
behavior. So existing interfaces can be increase without compromising backward compatibility by adding
extension methods to the interface, whose declaration would contain
instructions for finding the default implementation in the event that implementers
do not provide a method body. A key characteristic of extension methods is that
they are virtual methods just like other interface methods, but provide a
default implementation in the event that the implementing class does not
provide a method body.
Consider following example:Output:
Hello there!
In above code we added a defender
method sayHello() in Person
interface. So it was ok for class Sam to avoid declaring this methods body.
What about Multiple Inheritance?
Adding method definitions in
interfaces can add ambiguity in multiple inheritance. isn’t it? Well, it does.
However Java 8 handle this issue at Compile type. Consider below example:
In this example we have same defender
method sayHello in both interfaces
Person and Male. Class Sam implements these interfaces. So which version of sayHello will be inherited? We’ll if
you try to compile this code in Java 8, it will give following error.
ERROR:class Sam inherits
unrelated defaults for sayHello()
from types Person and Male class Sam implements Person, Male { ^ 1 error
So that solves multiple inheritance
problem. You cannot implement multiple interfaces having same signature of Java
8 default methods (without overriding explicitly in child class).
We can solve the above problem by overriding sayHello method in class
Sam.
It is also possible to explicitly
call method from child class to parent interface. Consider in above example you
want to call sayHello method from
Male interface when Sam.sayHello is
called. You can use super keyword to explicitly call the appropriate method.
Difference between default methods and abstract class
Ok, so far it looks good. In Java 8
we can have concrete methods within interfaces. right.. So how it is different
from Abstract classes? Remember an abstract class is a class that cannot be
instantiated (i.e. objects cannot be created of) and which may contain method
bodies. Default method in Java 8 looks similar to Abstract class isn’t it?
We’ll its different actually.
Abstract class can hold state of object. It can have constructors and member
variables. Whereas interfaces with Java 8 default methods cannot hold state. It
cannot have constructors and member variables. You should still use Abstract
class whenever you think your class can have state or you need to do something
in constructor. Default method should be used for backward compatibility. Whenever
you want to add additional functionality in an existing legacy interface you
can use default methods without breaking any existing implementation classes.
Also abstract classes cannot be root classes in Lambda expression. What?… I know that’s
confusing, but Lambda expressions are the reason why virtual extension methods
were introduced in Java 8. When a lambda expression is evaluated, the compiler
can infers it into the interface where default method is added.
0 comments:
Post a Comment