Most of us already know what is inheritance but its important that we know the different ways of inheritance. In this article, I will show you an example of concrete inheritance and interface inheritance.
Concrete Inheritance
Java doesn’t support multiple class inheritance but it does support multiple interface inheritance. First we should know what is concrete inheritance.
Concrete inheritance is inheritance of method implementations and member variables from a super-class. Java allows concrete inheritance from only a single super-class. For example:
A:
package javarticles.javainheritance; public class A { protected int mVar = 1; public A() { System.out.println("A's constructor"); } protected void doSomething() { System.out.println("A's doSomtehing(), var value: " + mVar); } }
B:
package javarticles.javainheritance; public class B extends A { public B() { System.out.println("B's constructor"); } protected void doSomething() { mVar = 2; super.doSomething(); System.out.println("B's doSomtehing()"); } }
Invoke B.doSomething()
JavaInheritanceTests:
package javarticles.javainheritance; import org.junit.Test; public class JavaInheritanceTests { @Test public void callB() { B b = new B(); b.doSomething(); } }
Output:
>A's constructor B's constructor A's doSomtehing(), var value: 2 B's doSomtehing()
C:
package javarticles.javainheritance; public class C extends B { public C() { System.out.println("C's constructor"); } protected void doSomething() { mVar = 3; super.doSomething(); System.out.println("C's doSomtehing()"); } }
Invoke C.doSomething()
@Test public void callC() { C c = new C(); c.doSomething(); }
Output:
A's constructor B's constructor C's constructor A's doSomtehing(), var value: 2 B's doSomtehing() C's doSomtehing()
Since Class
C
extends B
, C
, B
and A
are said to be in the same inheritance hierarchy.
Interface inheritance
Interface inheritance is nothing but the implementation of interfaces. A class may implement any number of interfaces.
For example:
Suppose I have three interfaces each representing one feature.
IFeature1:
package javarticles.javainheritance; public interface IFeature1 { public void doFeature1(); }
IFeature2:
package javarticles.javainheritance; public interface IFeature2 { public void doFeature2(); }
IFeature3:
package javarticles.javainheritance; public interface IFeature3 { public void doFeature3(); }
D:
package javarticles.javainheritance; public class D implements IFeature1 { @Override public void doFeature1() { System.out.println("do Feature1 in D"); } }
G:
package javarticles.javainheritance; public class G implements IFeature2 { @Override public void doFeature2() { System.out.println("do Feature2 in G"); } }
Class E
implements feature3. Since it extends D
it also ends up implementing feature1.
E:
package javarticles.javainheritance; public class E extends D implements IFeature3 { @Override public void doFeature3() { System.out.println("do Feature3 in E"); } }
Class hierarchies are rigid, use object composition instead
If we want class E
to inherit feature2, we won’t be able to do it through inheritance as E
already extends D
and we don’t want to change the inheritance hierarchy.
But we can do it through delegation using object composition. For example, Class E
is modified to delegate to G's
doFeature2()
E:
package javarticles.javainheritance; public class E extends D implements IFeature3, IFeature2 { private IFeature2 g = new G(); @Override public void doFeature3() { System.out.println("do Feature3 in E"); } @Override public void doFeature2() { g.doFeature2(); } }
Another example of object composition:
Class F
below implements all three features and delegates call to E's
features.
F:
package javarticles.javainheritance; public class F implements IFeature1, IFeature2, IFeature3 { private E e = new E(); @Override public void doFeature3() { e.doFeature3(); System.out.println("do Feature3 in F"); } @Override public void doFeature2() { e.doFeature2(); System.out.println("do Feature2 in F"); } @Override public void doFeature1() { e.doFeature1(); System.out.println("do Feature1 in F"); } }
This is a perfect example of object composition where functionality is inherited using delegation. This is more flexible than the concrete inheritance as we are not forced to extend a specific class just to inherit a method. Object composition allows the behavior of an object to be altered at run time through delegating part of its behavior to interface and allowing callers to set the implementation of that interface.
Download source code
In this article, we have seen examples of concrete inheritance and object composition.