7.5. Animal Example¶
In this section, we will work through another inheritance example involving animals.
Test Yourself
Take a moment to look over the UML class diagram below and answer the following questions. If you are unsure, do the best you can and write your thoughts in your notes.
How many inheritance relationships are present in the diagram?
In each inheritance relationship, which class is the parent and which is the child?
Look at each inheritance relationship. Intuitively, does an inheritance relationship seem appropriate?
Test Yourself Solution (open after answering the question above)
There is one inheritance relationship.
Dog
extendsAnimal
. The other relationships (uses
) indicate a general dependency, not inheritance.Dog
is the child class andAnimal
is the parent.When answering this question, ask yourself if the
is-a
relationship makes sense (the is-a test). Would you say thatDog
is anAnimal
? Yes! So, the inheritance relationship is appropriate.Another way to think about it is whether or not it is appropriate for
Dog
to inherit thegenus
andspecies
attributes and thegetGenus
andgetSpecies
methods. Again, the answer is “yes”!
To work through this example, perform the following steps:
Change into the
animal
subdirectory ofcs1302-inheritance
.Inspect the
.java
files undersrc
. In particular, familiarize yourself with the code for theAnimal
andDog
classes and compare the code to what you see in the UML diagram.Try the following before looking at the solution:
Test Yourself
Try Modifying
Dog.java
so that theDog
constructor invokes the parent constructor viasuper
.Hint: You will need to call the
Animal
constructor from within theDog
constructor using the literal values"Canis"
and"Lupus Familiaris"
as the genus and species, respectively. This will setup thegenus
andspecies
variable within anyDog
objects that are created.Test Yourself Solution (open after attempting the above)
The parent constructor (in the
Animal
class) takes two parameters:genus
andspecies
. Since we are invoking theAnimal
constructor on a type of animal where we know the exact genus and species, we can provide the literal values to the parent constructor.super("Canis", "Familiaris");
Warning
Since
genus
andspecies
are declared withprivate
visibility, you cannot access them directly (without a getter/setter):super.genus = "Canis"; super.species = "Lupus Familiaris";
Even if the visibility allowed you to write the lines above, you should avoid doing so! There is already code that sets up these variables. It is in the parent constructor. We should use
super
instead of duplicating that initialization code.Compile the
cs1302.animal.Animal
andcs1302.animal.Dog
classes, specifyingbin
as the default package for compiled code. Since there is a dependency between those two classes, remember to properly specify the class path, as needed, when you compile.Modify the
main
method in thecs1302.animal.Driver
class to create someDog
objects, then print out information about them:Dog bulldog = new Dog("Bulldog"); System.out.println(bulldog.getGenus()); System.out.println(bulldog.getSpecies()); System.out.println(bulldog.getBreed()); System.out.println();
Note
Because
Animal
variables are compatible withDog
objects, the datatype of thebulldog
variable could beAnimal
. However, if you made this change, you would no longer be able to call thegetBreed
method since that method is not available inAnimal
.Add code in
Driver.java
to createDog
objects for the following breeds: poodle, beagle, and pug. CallgetGenus
,getSpecies
, andgetBreed
on each breed as we did in the previous step.Compile the
cs1302.animal.Driver
class, specifyingbin
as the default package for compiled code and setting the class path as needed.Run the
cs1302.animal.Driver
class. You should see the following output:Canis Lupus Familiaris Bulldog Canis Lupus Familiaris Poodle Canis Lupus Familiaris Beagle Canis Lupus Familiaris Pug
As you can see from the output, each
Dog
object does containgenus
andspecies
(inherited fromAnimal
) that is set by theDog
constructor using the parameter values that you supplied. Furthermore, you can also see that eachDog
object has the getter methods that it inherited and that they return the values of the inherited variables.
Reminder
If a child constructor does not explicitly call a parent class
constructor via super
, then Java will automatically add
a call to super()
, i.e., it will attempt to invoke the parent’s
default constructor if it exists. We always recommend explicitly
calling a parent constructor, even if it’s just super()
, so that
it’s clear from reading the source code what your intent is.
Here is a video outlining the steps in this section if you got stuck:
7.5.1. Review Question¶
Test Yourself: Writing a Child Constructor
Given the UML Class Diagram below, write the constructor(s) for the child
class(es) in your notes. If the user inputs a negative value for an id,
the constructor(s) should throw an IllegalArgumentException
containing
an appropriate message.
Review Question 1 Solution (Open after answering the question above)
The constructor for the
Student
class should look like this:/** * Initializes the instance variables of a new {@code Student} object. * * @param name the name of the student. * @param age the age of the student. * @param studentId the student's id number. * @throws IllegalArgumentException if the student id number is a negative value. */ public Student(String name, int age, int studentId) { super(name, age); if (studentId < 0) { throw new IllegalArgumentException("The student id number must be nonnegative"); } // if this.studentId = studentId; } // Student
The constructor for the
Professor
class should look almost identical to theStudent
constructor withstudentId
replaced withemployeeId
. Can you think of a way to avoid redundancy by writing a method to check if the id is valid?