Multiple Inheritance Java Example
1. Introduction
Multiple inheritance means that a class inherits fields and methods from more than one parent. Java class does not support multiple inheritance as it cannot have more than one parent. Java supports multiple inheritance via interface because an interface can have more than one parent.
You can also check the Java Inheritance Tutorial in the following video:
The “diamond problem” is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a method in A that B and C have overridden, and D does not override it, then which version of the method does D inherit? There is no diamond problem in Java before it introduced default methods in Java 8.
In this example, I will create six interfaces and eight classes as the diagram showing here.

I will use them to demonstrate:
- “Diamond problem” in
DiamondProblemI–DiamondProblemIis extended fromInterface_BandInterface_Cwhich both extend fromInterface_Aand override thedefaultFoomethod.DiamondProblemImust override thedefaultFoomethod to void the diamond problem. - “Diamond problem” in
DiamondProblemC–DiamondProblemCimplementsInterface_BandInterface_Cwhich both override the samedefaultFoomethod. This caused a diamond problem too. We fix it by overriding thedefaultFoomethod. - A
ChildClassextends fromParent_Ywhich extends fromBaseClass. - A
MultiInheritanceIextends fromInterface_BandInterface_X. - A
CompositonClasshas aBaseClass.
2. Technologies Used
The example code in this article was built and run using:
- Java 11
- Maven 3.3.9
- Eclipse Oxygen
- Junit 4.12
3. Maven Project
3.1 Dependencies
I will include Junit in the pom.xml.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>java-multi-inheritance-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>11</release> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </project>
4. Interfaces
In this step, I will create six interfaces to demonstrate multiple inheritance and the diamond problem:
Interface_A– has a default method –defaultFooInterface_B– extends fromInterface_Aand overridesdefaultFooInterface_C– extends fromInterface_Aand overridesdefaultFooDiamondProblemI– extends fromInterface_BandInterface_C. Since both parent interfaces have the same default method –defaultFoo.DiamondProblemImust overridedefaultFooto avoid the “diamond problem”Interface_X– has a defaultdefaultFooNAandfoo1MultiInheritanceI– extends fromInterface_BandInterface_X
4.1 Interface_A
In this step, I will create an Interface_A which has two methods:
defaultFoo– default methodfoo1
Interface_A.java
package jcg.zheng.demo.api;
public interface Interface_A {
default String defaultFoo(String msg) {
return "Interface_A.defaultFoo is invoked for " + msg;
}
String foo1(String message);
}
4.2 Interface_B
In this step, I will create an Interface_B which extends from Interface_A and with two methods:
defaultFoo– overrides the inherited default methodfoo2
Interface_B.java
package jcg.zheng.demo.api;
public interface Interface_B extends Interface_A {
@Override
default String defaultFoo(String msg) {
return "Interface_B.defaultFoo is invoked for " + msg;
}
String foo2(String subjectName);
}
4.3 Interface_C
In this step, I will create an Interface_C which extends from Interface_A and three methods:
defaultFoo– overrides default methodfoo2foo3
Interface_C.java
package jcg.zheng.demo.api;
public interface Interface_C extends Interface_A {
@Override
default String defaultFoo(String msg) {
return "Interface_C.defaultFoo is invoked for " + msg;
}
String foo2(String dummyData);
String foo3(String dummyData);
}
4.4 Interface_X
In this step, I will create an Interface_X which has two methods:
defaultFooNA– default methodfoo1
Interface_X.java
package jcg.zheng.demo.api;
public interface Interface_X {
default String defaultFooNA(String msg) {
return "Interface_X.defaultFooNA is invoked";
}
String foo1(String subjectName);
}
4.5 Multiple Inheritance Interface
In this step, I will create an interface which extends from both Interface_X and Interface_B. There are no duplicate defaults methods from both interfaces.
MultiInheritanceI.java
package jcg.zheng.demo.api;
public interface MultiInheritanceI extends Interface_X, Interface_B {
}
4.6 Diamond Problem
In this step, I will create an interface called DiamondProblemI which extends from Interface_B and Interface_C. It caused the diamond problem because both Interface_B and Interface_C override the defaultFoo method. DiamondProblemI must override defaultFoo.
DiamondProblemI.java
package jcg.zheng.demo.api;
public interface DiamondProblemI extends Interface_B, Interface_C {
@Override
default String defaultFoo(String msg) {
return Interface_B.super.defaultFoo(msg);
}
}
5. Classes
In this step, I will create eight classes:
BaseClass– It’s the base class for bothParent_XandParent_Y.Parent_X– It extends fromBaseClass.Parent_Y– It extends fromBaseClass.ChildClass– It extends fromParent_X.CompositionClass– It has a field whose type isBaseClass.DiamondProblemC– It’s a class which implements bothInterface_BandInterface_Cwhich must override thedefaultFoomethod to fix the diamond problem.DiamondProblemandMultiInheritanceIClassimplement interface which extends from more than one interface.
5.1 Base Class
In this step, I will create a BaseClass which has two data members and one method:
private String someData– declares private data member is a good practice.protected String shadowingData–protectedmembers are inherited by the child class. It will be hidden if the child class has the same variable name.public String foo1(String msg)– a method in base class is inherited by all its children. When it is changed, all children classes get changed too.
BaseClass.java
package jcg.zheng.demo.api.impl;
public class BaseClass {
private String someData;
protected String shadowingData;
public String getSomeData() {
return someData;
}
public void setSomeData(String data) {
this.someData = data;
}
public String foo1(String message) {
return "BaseClass.foo1 " + message;
}
}
5.2 Parent_X Class
In this step, I will create a Parent_X class which extends from BaseClass. It has the name field and foo2 method.
Parent_X.java
package jcg.zheng.demo.api.impl;
public class Parent_X extends BaseClass {
private String name;
public String foo2(String subjectName) {
setName(subjectName);
return "Hello, " + subjectName;
}
public String getName() {
return name;
}
public void setName(String cName) {
this.name = cName;
}
}
5.3 Parent_Y Class
In this step, I will create a Parent_Y class which extends from BaseClass. It has the field – shadowingData which has the same name with a field in BaseClass. The BaseClass.shadowingData is inaccessible from Parent_Y.
Parent_Y.java
package jcg.zheng.demo.api.impl;
public class Parent_Y extends BaseClass {
private String message;
protected String shadowingData;
public Parent_Y(String message) {
super();
this.message = message;
}
public String foo2(String data) {
return message + " foo2: " + data;
}
public String foo3(String data) {
return message + " foo3: " + data;
}
}
5.4 Child Class
In this step, I will create a ChildClass which extends from Parent_Y.
ChildClass.java
package jcg.zheng.demo.api.impl;
public class ChildClass extends Parent_Y {
public ChildClass(String message) {
super(message);
}
}
5.5 Multiple Inheritance Class
In this step, I will create a MultiInheritanceIClass which implements MultiInheritanceI.
MultiInheritanceIClass.java
package jcg.zheng.demo.api.impl;
import jcg.zheng.demo.api.MultiInheritanceI;
public class MultiInheritanceIClass implements MultiInheritanceI {
@Override
public String foo1(String subjectName) {
return this.getClass() + " foo1";
}
@Override
public String foo2(String subjectName) {
return this.getClass() + " foo2";
}
}
5.6 Diamond Problem Class
In this step, I will create a DiamondProblem which implements DiamondProblemI.
DiamondProblem.java
package jcg.zheng.demo.api.impl;
import jcg.zheng.demo.api.DiamondProblemI;
public class DiamondProblem implements DiamondProblemI {
@Override
public String foo1(String message) {
return this.getClass() + " foo1";
}
@Override
public String foo2(String dummyData) {
return this.getClass() + " foo2";
}
@Override
public String foo3(String dummyData) {
return this.getClass() + " foo3";
}
}
5.7 Diamond Problem Interface Class
In this step, I will create a DiamondProblemC which implements Interface_B and Interface_C. DiamondProblemC must override the defaultFoo method to avoid the diamond problem.
DiamondProblemC.java
package jcg.zheng.demo.api.impl;
import jcg.zheng.demo.api.Interface_B;
import jcg.zheng.demo.api.Interface_C;
public class DiamondProblemC implements Interface_B, Interface_C {
@Override
public String defaultFoo(String msg) {
return Interface_C.super.defaultFoo(msg);
}
@Override
public String foo1(String message) {
return this.getClass() + " foo1";
}
@Override
public String foo2(String subjectName) {
return "foo2 " + subjectName;
}
@Override
public String foo3(String data) {
return ("foo3 " + data);
}
}
5.8 CompositionClass
In this step, I will create a CompositionClass which has a BaseClass object member and a field whose name matches the same in BaseClass. But BaseClass.shadowingData will not be hidden from CompositionClass. If the BaseClass does not meet the requirement, it’s easy to switch to a new class without considering the impact to others.
CompositionClass.java
package jcg.zheng.demo.api.impl;
public class CompositionClass {
//if BaseClass does not meet the requirement, then you can include a different object with the more suitable method
private BaseClass bCls;
protected String shadowingData;
public BaseClass getbCls() {
return bCls;
}
public void setbCls(BaseClass bCls) {
this.bCls = bCls;
}
}
6. JUnit Test
In this step, I will demonstrate the multiple inheritance via Junit tests.
6.1 Child Test
In this step, I create a ChildTest to demonstrate that a class can inherit from more than one level of inheritance. It also shows that shadowing variable is a bad practice because there is no way to set its value. See line 26 for details.
ChildClassTest.java
package jcg.zheng.demo.api.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
public class ChildClassTest {
private ChildClass testClass = new ChildClass("Mary");
@Test
public void foo2() {
assertEquals("Mary foo2: Zheng", testClass.foo2("Zheng"));
}
@Test
public void foo3() {
assertEquals("Mary foo3: Zheng", testClass.foo3("Zheng"));
}
@Test
public void shadowingData_is_bad_practice() {
testClass.shadowingData = "Test";
assertEquals("Test", ((Parent_Y) testClass).shadowingData);
assertNull(((BaseClass) testClass).shadowingData);
}
}
Junit Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.api.impl.ChildClassTest Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.145 sec Results : Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
6.2 Parent_X Test
In this step, I will create a test for Parent_X.
Parent_XTest.java
package jcg.zheng.demo.api.impl;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class Parent_XTest {
private Parent_X testClass = new Parent_X();
@Test
public void foo1() {
// if BaseClass.foo1 not meet the sub class's need. then you must be change at
// the super class which other subclass may not agree with you!
assertEquals("BaseClass.foo1 Test", testClass.foo1("Test"));
}
@Test
public void foo2() {
assertEquals("Hello, Zheng", testClass.foo2("Zheng"));
}
@Test
public void test_inherited_method() {
testClass.setName("Local data");
testClass.setSomeData("Common data");
assertEquals("Common data", testClass.getSomeData());
assertEquals("Local data", testClass.getName());
}
}
Junit Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.api.impl.Parent_XTest Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.222 sec Results : Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
6.3 Parent_Y Test
In this step, I will create a test for Parent_Y. Please note that the line 39 – the BaseClass.shadowingData is inaccessible.
Parent_YTest.java
package jcg.zheng.demo.api.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
public class Parent_YTest {
private Parent_Y testClass = new Parent_Y("Mary");
@Test
public void foo1() {
// if BaseClass.foo1 not meet the sub class's need. then you must be change at
// the super class which other subclass may not agree with you!
assertEquals("BaseClass.foo1 Zheng", testClass.foo1("Zheng"));
}
@Test
public void foo2() {
assertEquals("Mary foo2: Zheng", testClass.foo2("Zheng"));
}
@Test
public void foo3() {
assertEquals("Mary foo3: Zheng", testClass.foo3("Zheng"));
}
@Test
public void inherited_methods() {
testClass.setSomeData("Common Data");
assertEquals("Common Data", testClass.getSomeData());
}
@Test
public void shadowingData_is_bad_as_it_hide_fields() {
testClass.shadowingData = "Test";
assertEquals("Test", testClass.shadowingData);
assertNull(((BaseClass) testClass).shadowingData);
}
}
Junit Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.api.impl.Parent_YTest Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.171 sec Results : Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
6.4 Multiple Inheritance Test
In this step, I will create a test for MultiInheritanceClass.
MultiInheritanceIClassTest.java
package jcg.zheng.demo.api.impl;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class MultiInheritanceIClassTest {
private MultiInheritanceIClass testClass = new MultiInheritanceIClass();
@Test
public void defaultFoo() {
assertEquals("Interface_B.defaultFoo is invoked for Mary", testClass.defaultFoo("Mary"));
}
@Test
public void defaultFooNA() {
assertEquals("Interface_X.defaultFooNA is invoked", testClass.defaultFooNA("Mary"));
}
@Test
public void foo1() {
assertEquals("class jcg.zheng.demo.api.impl.MultiInheritanceIClass foo1", testClass.foo1("Test"));
}
@Test
public void foo2() {
assertEquals("class jcg.zheng.demo.api.impl.MultiInheritanceIClass foo2", testClass.foo2("Test"));
}
}
Junit Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.api.impl.MultiInheritanceIClassTest Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.175 sec Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
6.5 Diamond Problem Test
In this step, I will create a test for DiamondProblem.
DiamondProblemTest.java
package jcg.zheng.demo.api.impl;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class DiamondProblemTest {
private DiamondProblem testClass = new DiamondProblem();
@Test
public void defaultFoo() {
assertEquals("Interface_B.defaultFoo is invoked for Mary", testClass.defaultFoo("Mary"));
}
@Test
public void foo1() {
assertEquals("class jcg.zheng.demo.api.impl.DiamondProblem foo1", testClass.foo1("Zheng"));
}
@Test
public void foo2() {
assertEquals("class jcg.zheng.demo.api.impl.DiamondProblem foo2", testClass.foo2("Test"));
}
@Test
public void foo3() {
assertEquals("class jcg.zheng.demo.api.impl.DiamondProblem foo3", testClass.foo3("Test"));
}
}
Junit Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.api.impl.DiamondProblemTest Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.159 sec Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
6.6 Diamond Problem Interface Test
In this step, I will create a test for DiamondProblemC.
DiamondProblemCTest.java
package jcg.zheng.demo.api.impl;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class DiamondProblemCTest {
private DiamondProblemC testClass = new DiamondProblemC();
@Test
public void defaultFoo() {
assertEquals("Interface_C.defaultFoo is invoked for Mary", testClass.defaultFoo("Mary"));
}
@Test
public void foo1() {
assertEquals("class jcg.zheng.demo.api.impl.DiamondProblemC foo1", testClass.foo1("Zheng"));
}
@Test
public void foo2() {
assertEquals("foo2 Zheng", testClass.foo2("Zheng"));
}
@Test
public void foo3() {
assertEquals("foo3 Zheng", testClass.foo3("Zheng"));
}
}
Junit Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.api.impl.DiamondProblemCTest Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.213 sec Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
6.7 Composition Test
In this step, I will create a test for CompositionClass. Please note that line 15 and 19 show that BaseClass.shadowingData is accessible when it is used as a composition than inheritance.
CommonService.java
package jcg.zheng.demo.api.impl;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class CompositionClassTest {
private CompositionClass testClass = new CompositionClass();
@Test
public void composition_not_shadowingData() {
BaseClass bCls = new BaseClass();
bCls.setSomeData("Test");
bCls.shadowingData = "BaseClass.shadowingData is not shadowing at composition";
testClass.setbCls(bCls );
assertEquals("Test", testClass.getbCls().getSomeData());
assertEquals("BaseClass.shadowingData is not shadowing at composition", testClass.getbCls().shadowingData);
}
}
Junit Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.api.impl.CompositionClassTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.117 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
7. Summary
In this example, I demonstrated how Java supports multiple inheritance via interface and explained how the diamond problem is introduced after Java 8 introduced the default method. I also demonstrated that using object with composition has less impact than inheritance.
8. Download the Source Code
This example consists of a Maven project which demonstrates multiple inheritance in Java.
You can download the full source code of this example here: Multiple Inheritance Java Example


