As you probably know, Java
has no mechanism for "true" multiple inheritance like C++, but it can be somewhat
"simulated" using abstract classes and interfaces.
Let us suppose that we want to create a class called
Ballerina. A ballerina has attributes like name, age, height and weight and behaviors like dancing, running, jumping and sleeping. The Ballerina class should inherit two classes:
Athlete and
Dancer. The Athlete and Dancer classes have some things in common like the fact that both athletes and dancers have a name and an age and they both have to sleep. The thing that differentiates athletes from dancers is the fact that athletes run and jump, while dancers have to dance.
In C++, we could had the Ballerina class inherit the Athlete and Dancer classes directly through multiple inheritance (and since the base classes have common attributes one of them would had been inherited virtually), but like I said before this mechanism is not available in Java.
In order to have a
good OO design, we need to create a base class which should contain the common attributes and behaviors found in athletes and dancers. Since such a class doesn't need to be instantiated, it should be declared as abstract. We shall call this class
Human.
public abstract class Human
{
private String name;
private int age;
public Human(String name, int age)
{
this.name = name;
this.age = age;
}
public abstract void sleepNow();
}
If we wouldn't need to create the Ballerina class, we could simply create an
Athlete class to extend the Human class. But since both ballerinas and athletes run and jump, we should declare first an interface for this behaviors.
public interface IAthlete
{
public void run();
public void jump();
}
The class Athlete should be then like:
public class Athlete extends Human implements IAthlete
{
public Athlete(String name, int age)
{
super(name, age);
}
public void sleepNow()
{
System.out.println("Athlete sleeps");
}
public void run()
{
System.out.println("Athelete runs");
}
public void jump()
{
System.out.println("Athlete jumps");
}
}
We shall apply the same logic for dancers. First we shall define an interface to contain the specific behaviors of a
Dancer:
public interface IDancer
{
public void dance();
}
And then we shall define a class to implement this behaviors:
public class Dancer extends Human implements IDancer
{
public Dancer(String name, int age)
{
super(name, age);
}
public void dance()
{
System.out.println("Dancer dances");
}
public void sleepNow()
{
System.out.println("Dancer sleeps");
}
}
Now, we can define the
Ballerina class as a class that inherits the Human abstract class and implements the behavior of dancers and athletes:
public class Ballerina extends Human implements IAthlete, IDancer
{
private int height, weight;
public Ballerina(String name, int age, int height, int weight)
{
super(name, age);
this.height = height;
this.weight = weight;
}
public void run()
{
System.out.println("Ballerina runs");
}
public void dance()
{
System.out.println("Ballerina dances");
}
public void jump()
{
System.out.println("Ballerina jumps");
}
public void sleepNow()
{
System.out.println("Ballerina sleeps");
}
}
Even if
the Ballerina class can't inherit directly from Dancer and Athelete, we can use the interfaces IAthlete and IDancer "like base classes" to reference Athlete and Ballerina object respectively Dancer and Ballerina objects.
IDancer d1 = new Dancer("John",32);
IDancer d2 = new Ballerina("Joanna",20,170,55);
d1.dance();
d2.dance();
IAthlete a1 = new Athlete("Mike",22);
IAthlete a2 = (IAthlete)d2; //Ballerina implements both interfaces
a1.jump();
a2.jump();
//Output
//Dancer dances
//Ballerina dances
//Athlete jumps
//Ballerina jumps
Also it is to note that
a Human reference can reference both Dancer and Athlete and also Ballerina.
Human h1 = new Dancer("John",32);
Human h2 = new Athlete("Jimmy",33);
Human h3 = new Ballerina("Irina",21,170,55);
h1.sleepNow();
h2.sleepNow();
h3.sleepNow();
//Output
//Dancer sleeps
//Athlete sleeps
//Ballerina sleeps