7.8. Inheritance and Polymorphism

As mentioned in previous sections, we can leverage polymorphism in inheritance hierarchies as well. For example, variables of type Animal can reference objects of type Dog. Additionally, if we extended this hierarchy further by adding other animals as child classes to Animal, the compatibility would work for those classes as well. Imagine we extended the inheritance hierarchy from the previous section to like this (some methods and variables removed for clarity):

hide circle
set namespaceSeparator none
skinparam classAttributeIconSize 0

package "cs1302.animal" {
   Animal <|--left Dog: extends
   Animal <|-- Cat: extends
   Animal <|-- Frog: extends
   Animal <|-- Giraffe: extends
   Animal <|-- Elephant: extends

   abstract class Animal << abstract >> {
        +<<abstract>>{abstract} describe(): void
        +<<abstract>>{abstract} makeSound(): void
   }

   class Dog {
        +describe(): void
        +makeSound(): void
   }
   class Cat {
        +describe(): void
        +makeSound(): void
   }
   class Elephant {
        +describe(): void
        +makeSound(): void
   }
   class Giraffe {
        +describe(): void
        +makeSound(): void
   }
   class Frog {
        +describe(): void
        +makeSound(): void
   }

   hide Dog fields
   hide Cat fields
   hide Elephant fields
   hide Giraffe fields
   hide Animal fields
   hide Frog fields
}

Assuming that the makeSound method in each child class is implemented and prints an appropriate “sound” for each animal, we could leverage polymorphism to write code using an Animal variable like this:

public static void animalInfo (Animal currentAnimal) {
   System.out.println("More information about the animal:\n"):

   currentAnimal.describe();

   System.out.println("The animal lets out a loud: " + currentAnimal.makeSound());
} // animalInfo

Now, we could call this method with animals of any type as this method is written to work for every type of object compatible with Animal! More specifically, we could do something like this in main if our animalInfo method is contained in a class called Driver:

public static void main(String[] args) {
   Dog fido = new Dog("Juno", "Jack Russell");
   Animal garfield = new Cat("Garfield");

   // AnimalInfo works for either variable / object!
   Driver.animalInfo(fido);
   Driver.animalInfo(garfield);
} // main

7.8.1. Review Questions

Review Question 1

In English, describe what this code does:

public static void makeSounds (Animal[] animals) {
   for (Animal individual: animals) {
      individual.makeSound();
   } // for
} // animalInfo
Review Question 1 Solution (open after answering the question above)

This method would print the sound for all animals in the specified array. Note: Each array index contains a reference to an object that is compatible with Animal. There is no guarantee that all objects are of the same type! The array could contain references to Frog objects, Cat objects, etc.

Review Question 2

Fill in the method below to test if the animals array contains a reference to an object of type Giraffe. It will be useful to know that the genus of giraffes is “Giraffa”.

fill in the method with your solution.
/**
 * Returns true if the specified {@code Animal} array contains
 * a reference to a {@code Giraffe} object.
 *
 * @param animals the array of animals to search.
 * @return true if the array contains a giraffe and false otherwise.
 */
public static boolean containsGiraffe (Animal[] animals) {

   // Your code here...

} // containsGiraffe
Review Question 2 Solution (open after answering the question above)

This is one possible solution. There are many ways to write this code correctly. If you have a solution you would like us to verify, feel free to post on the course Piazza page. Sharing source code to textbook exercises is allowed.

/**
 * Returns true if the specified {@code Animal} array contains
 * a reference to a {@code Giraffe} object.
 *
 * @param animals the array of animals to search.
 * @return true if the array contains a giraffe and false otherwise.
 */
public static boolean containsGiraffe (Animal[] animals) {
   for (Animal individual: animals) {
      if (individual.getGenus().equals("Giraffa")) {
         return true;
      } // if
      return false;
   } // for
} // containsGiraffe

Since the parent data type (Animal) is compatible with all of the child class types, the Animal references in the animals array can refer to objects of any of the child classes.