In inheritance, objects belong to the same category.
For example:
A dog is an animal
A bird is an animal
A fish is an animal
A dog, cat, and fish are not the same thing, but they belong to the same category of “object” (animal)
Because dog, cat, and fish belong to the same category, they share common characteristics and behaviours.
For example:
All animals have a name
All animals are warm blooded
All animals eat grass
All animals sleep at night
Although dog, cat, and fish share these characteristics, they are different types of animals. Thus, in addition to the common characteristics, they have additional characteristics and behavioursthat are unique to themselves.
For example:
A dog barks, but a bird and fish cannot bark
A bird can fly, but a dog and fish cannot
A fish lives in water, but a dog and bird do not
A dog has 4 legs, birds have 2 legs, fish have 0 legs
UML
In object oriented programming, we model these relationships using the concept of inheritance. In UML, inheritance looks like this:
Animal is known as the base class, parent class, or superclass
Bird is known as a subclass or child class, or derived class
If there is more than one child class, the UML looks like this:
Defining a Parent and Child Class
1. Define the parent class.
class Vehicle() {
var currentSpeed:Int = 60
init {
println("Vehicle created, initial speed is ${this.currentSpeed} km/h")
}
fun accelerate() {
// all vehicles can accelerate
this.currentSpeed = this.currentSpeed + 5
println("[ACCELERATING!] The speed of the car is ${this.currentSpeed} km/h")
}
fun brake() {
// all vehicles can brake
this.currentSpeed = 0
println("[BRAKING!] The speed of the car is ${this.currentSpeed} km/h")
}
}
2. Mark the parent class with the open keyword
open class Vehicle() {
...
}
3. Create a child class
class RaceCar() {
init {
println("Racecar created")
}
}
4. Associate the child class with the parent class in the class definition
class RaceCar():Vehicle() {
init {
println("Racecar created")
}
}
5. Final code:
open class Vehicle() {
var currentSpeed:Int = 0
init {
println("Vehicle created, initial speed is ${this.currentSpeed} km/h")
}
fun accelerate() {
// all vehicles can accelerate
this.currentSpeed = this.currentSpeed + 5
println("[ACCELERATING!] The speed of the car is ${this.currentSpeed} km/h")
}
fun brake() {
// all vehicles can brake
this.currentSpeed = 0
println("[BRAKING!] The speed of the car is ${this.currentSpeed} km/h")
}
}
class RaceCar():Vehicle() {
init {
println("Racecar created")
}
}
Instantiating a Parent Class and Child Class
To create an instance of the parent class (parent object) using explicit variable declaration
val v1:Vehicle = Vehicle()
println("v1's data type is ${v1::class.java.simpleName}")
2. To create an instance of the child class (child object) using explicitvariable declaration
val r1:RaceCar = RaceCar()
println("r1's data type is ${r1::class.java.simpleName}")
3. Final code:
open class Vehicle() {
var currentSpeed:Int = 60
init {
println("Vehicle created, initial speed is ${this.currentSpeed} km/h")
}
fun accelerate() {
// all vehicles can accelerate
this.currentSpeed = this.currentSpeed + 5
println("[ACCELERATING!] The speed of the car is ${this.currentSpeed} km/h")
}
fun brake() {
// all vehicles can brake
this.currentSpeed = 0
println("[BRAKING!] The speed of the car is ${this.currentSpeed} km/h")
}
}
class RaceCar():Vehicle() {
init {
println("Racecar created")
}
}
fun main() {
// create a vehicle
val v1:Vehicle = Vehicle()
println("v1's data type is ${v1::class.java.simpleName}")
// create a race car
val r1:RaceCar = RaceCar()
println("r1's data type is ${r1::class.java.simpleName}")
}
Result
Notice that the parent constructor’s initialization block is called BEFORE the child class’
Vehicle created, initial speed is 0 km/h
Racecar created
r1's data type is RaceCar
Order of Instantiation
During the construction of the child class:
parent class’ constructors are always evaluated and executed first.
The child class’s constructors are evaluated/executed second.
Inheriting Properties and Behaviours
The child class will inherit all behaviours and properties of the parent class.
// race car has a current speed
println(r1.currentSpeed)
// race car can accelerate
r1.accelerate()
// race car can brake
r1.brake()
Expected output:
60
[ACCELERATING!] The speed of the car is 65 km/h
[BRAKING!] The speed of the car is 0 km/h
Adding Additional Properties and Behaviours
A child class can extend the behaviour of the parent class by adding additional behaviours and properties.
These additional behaviours and properties can only be used by the child class, not the parent class.
Example: Tesla Child Class
class Tesla():Vehicle() {
// ADDITIONAL PROPERTY
// teslas are electric, so they have a battery capacity
var batteryCapacity = 2500
init {
println("Tesla created")
}
// ADDITIONAL BEHAVIOUR (METHOD)
// teslas have a self driving feature
fun selfDrive() {
println("Self driving mode activated. The car is driving by itself!")
}
}
Using the Tesla’s unique properties and methods:
// creating a Tesla
val t1:Tesla = Tesla()
// 1. tesla has a speed
println(t1.currentSpeed)
// 2. tesla can accelerate
t1.accelerate()
// 3. tesla can brake
t1.brake()
// 4. tesla ALSO has a battery capacity
println(t1.batteryCapacity)
// 5. tesla ALSO can self drive
t1.selfDrive()
Output:
Tesla created
60
[ACCELERATING!] The speed of the car is 65 km/h
[BRAKING!] The speed of the car is 0 km/h
2500
Self driving mode activated. The car is driving by itself!
These properties and methods are UNIQUE to Tesla objects:
The parent class does not have these properties / methods
Other child classes do not have these properties / methods
Example: Other classes cannot access Tesla’s features
// race cars and vehicles do not have these features