Introduction
Today’s lab will be covering the basics of Inheritance.
What is inheritance? Inheritance is a concept that explains how one class gains the attributes of another, including the inherited class’s methods and variables. This allows us to define more complex classes through the use of more general base classes. It also eliminates redundant code that could appear in multiple similar classes.
So how does this work? Inheritance works by taking existing code and building on top of it, and programmers can define a class to “inherit” existing code from another class by using the keyword “extends” in the class header.
For example, let’s say you have a class named Animal, and you wanted to make a class for Birds. Since Birds and Animals share many of the same base attributes, you could extend the Animal class and add any additional parts needed to the Bird class. Let’s take a look.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Animal {
public String noise;
public int age;
private String name;
public Animal(String noise, int age, String name){
this.noise = noise;
this.age = age;
this.name = name;
}
public String getName() {
return name;
}
public void speak(){
System.out.println("My name is " + name);
System.out.println("I am " + age + " years old");
System.out.println("I say " + noise);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Bird extends Animal {
public double height;
public String color;
public Bird(String noise, int age, String name, double height, String color){
super(noise, age, name);
this.height = height;
this.color = color;
}
public void printBird(){
System.out.printf("Hello! I am %s and I am a %s Bird! %s!", this.getName(), this.color, this.noise);
}
public void speak(){
super.speak();
System.out.println("I am " + color);
System.out.println("I am " + height + " inches tall");
}
}
Some terminology
A base class, superclass, and parent class all mean the same thing - the class that is being extended.
A derived class, subclass, and child class also all mean the same thing - the class that is doing the extending.
In the above example the Animal is the class being extended and Bird is the class doing the extending. So in this example we could say:
- Animal is the parent class
- Animal is the superclass
- Animal is the base class
We could also say:
- Bird is the child class of Animal
- Bird is the subclass of Animal
- Bird is the derived class of Animal
Inheriting a Class
When using inheritance, we will be talk in terms of the relation between parent and child classes.
The parent class is the class that is inherited from. In the previous example, Animal is the parent class, as it is the class being extended, as seen when Bird extends Animal. The parent class is often capable of being an object on its own.
For example, you can have an object of type Animal, without it needing to be a Bird. A Bird however has many of the same traits as an Animal, but it needs a few more specific pieces of information to be usable, such as the height and color, things that are less important to the basic Animal.
The child class is the class that is actually inheriting, taking existing properties and methods from an above parent class. This allows the child class the ability to gain certain traits and tools from the parent class without having to copy and paste large chunks of code.
In the previous example, Bird needs some of the traits that Animal has, such as name, age, and noise, however rewriting this code is inefficient. Instead of duplicating code, we use the keyword extends as well as the name of the class we want to extend Animal (thus giving us Bird extends Animal) which tells the system to bring anything from Animal that can be inherited, such as public class variables and methods.
Super
The keyword super is used to tell the system that you want to use something from the parent class. It is used to call methods from the parent class, and to access the parent class constructor.
In a constructor
When inheriting a class, an additional step must be taken within the constructor.
The FIRST LINE inside the subclass’s constructor should always be a call to the superclass constructor.
This is because we need to invoke the constructor to set all of the information in the parent, in order to use our child class, so we call the parent’s
constructor to set all of the needed information. If the parent class has a constructor with no parameters your call will look like this:
super();
But if the parent class has a constructor with parameters, the call will look like this:
super( *parameter list* );
Using a method
When wanting to use a method inside the superclass, you can use a call such as super.methodName();
. This will call the method in the super class
just like calling any other method. This comes in handy when overriding methods. A call to a method using the keyword super specifies that you
want to use a method from the superclass, not a method from the class you are currently in.
For example, in the Bird class we can call this.getName() because we have no other getName method, except the one in our parent class. Therefore, the system knows to look in the superclass. BUT, in the speak method, we have to use super.speak() because if we had used the keyword this, we would’ve gotten Bird’s speak method, not Animal’s. Because we have methods of the same name, we must specify the one we want, using the keyword super.
How to Access Information from the Superclass
Now that data has been inherited from the parent class, let’s talk about what you have access to and how to access it. When you inherit from a class you inherit all of the information belonging to that class, however you do not always inherit the right to access it. This may sound a little confusing, so let’s go over it.
Here’s what child classes will always get access to: any public or protected variables or methods.
After inheriting, public information stays public, but protected information now becomes private. For example, something that was protected in the Animal class is now seen as private in the Bird class after inheritence.
Private variables and methods are a slightly different story. Although the child class inherits the information stored in the private methods and variables, it lacks the ability to interact with or modify the information stored in those variables without the use of a getter or setter. Just remember that the keyword private means that no one outside of the class has access to it, not even a child class.
In the Animal/Bird example, Bird gains the ability to freely access and modify the values stored in noise and age. However, it is only able to interact with name through the getName and setName Methods. This is why getters and setters are so important. Getters and setters allow for child classes to interact with private inherited information.
Overriding Methods
When you inherit from a class, along with it comes all of the methods and variables the superclass had, but what if you want to write a method with the same name as one of the superclass’s methods?
Well, you can just override it, by writing a new method with the same name in the subclass. When Java is compiling the code it can tell that the subclass is overriding the method from the superclass and will instead only use the subclass’s version of that method. For example in the Animal/Bird example, Bird overrides the speak() method found in Animal. Overriding a method is especially common with methods such as toString() and equals().
Inheriting from a subclass
It is possible to inherit from a subclass, and in fact all basic inheritance does so. All classes, regardless of whether the intent of them is to create an object or not, inherit from the built-in Java Object Class. Object is the base class that provides a multitude of necessary methods needed for all java classes to function including, toString() and equals(otherObject).
Multiple levels of inheritance are very common, especially when multiple items may have shared core attributes but have specific needs within their own class. When inheriting from a class that is also inheriting from another class, the new subclass gains all of the information stored within both the superclass and the superclass’s superclass, following the same rules as normal inheritance.
We will talk about this more in depth later but for now, draw out an inheritance hierarchy if you are confused about the structure of the inheriting classes. The top class should be the main class that is extended from, and those below it are the subclasses which are extending from it.
instanceof
instanceof is a special keyword used for comparing objects, such as in the equals method, which compares whether two objects of a specific class are equal. Instead of trying and compare two things that are not of the same type, we first use casting and instanceof to see if two things are comparable.
So, the equals method takes an argument of type Object, which means it can be any type of object, so it is not necessarily the same type as the class calling the equals method. We then have to use instanceof to check if the variable coming in is a valid type to be compared to. We use instanceof to make sure we can safely type cast our other object without errors.
Here is an example equals method, for the Bird class.
This method first checks if the other object is a Bird, and if it’s not a Bird, then we can’t compare it to our Bird object, so we return false. Next, we do a simple comparison between some of the class variables of the two objects. This allows you to specify how closely related two objects need to be in order to be defined as equal.
For example, if you have two Birds with different heights but the same color you could say they are equal. This ability to define the equals method for each class gives a great degree of flexibility.
Now on to the lab!
Here are the lab instructions:
Step 1
You will be completing a class named Employee that will inherit from the class Person.
- Finish the extends statement in the Employee class header
- Write the Employee constructor don’t forget your call to super
- Create two private class variables: an int id, and a double hourlyPay
- Since they are both private variables, write getters and setters for both variables: getId, getHourlyPay, setId, setHourlyPay
Step 2
In the Employee class, complete the getRaise method. This method gives a raise to the user, increasing their total hourly pay by 15%. This method also updates the hourly pay class variable you made as well. Finally return the value of the employee’s new hourlyPay.
Step 3
Inside the Employee class complete the method payDay. This method calculates how much the employee earned for the week. First calculate their pay, if the employee worked more than 40 hours, then any hour OVER 40 is worth 1.5 times their normal pay, this is considered overtime pay, otherwise their pay is as normal. Return their total pay for the week.
Example: if I worked 45 hours this week, I would get 5 hours of overtime pay and 40 hours of normal pay.
Step 4
Inside the Employee class, let’s override the toString method.
For the toString method, you will use the same basic output from Person toString method but add two new lines. Using Person toString method as a starting point, the first two lines of our new toString method will look like:
Name: first_name last_name
They are height_feet’ height_inches“
You will now also add the lines:
They make $hourly_pay
They have the employee ID id_number
Each line should be followed by a new line, including the last character. The hourly pay should also be formatted with two digits after the decimal place. (Remember String.format()?)
HINT will a call to super help?
Step 5
Inside the Employee class, we will now override the equals method.
The method will return true if the employees share the same ID AND their last names are the same Otherwise, the two are not the same and the method will return false.
HINT Go back and look at the example given above for instanceof … does that look similar to what we are trying to do?