AbstractionJ8 Home « Abstraction
In this lesson we continue our investigation of OO concepts by looking at abstraction. In the previous five lessons we looked at inheritance and how it enables us to avoid code duplication by setting a protocol for a group of
classes. We used the extends
keyword to subclass this common behaviour into more specific classes, whilst still being able to use the more abstract mechanics of the superclass. We set up an
inheritance hierarchy to illustrate the mechanics of inheritance and how method invocation works. Something isn't right with our hierarchy though, so let's take a look at this with the following slideshow:
Abstract Classes Top
In our class inheritance tree for Vehicle Town we need to stop instantiation of the Vehicle
and Truck
class, as these are abstractions for their subclasses. To do this we use the abstract
keyword in the class definition. This means that only static
members of this class can ever be used unless we create a non-abstract subclass. So abstract classes need to be extended if we
want to use any non-static members within the class. This also means that you can't declare a class as both abstract
and final
or the compiler complains. Non-abstract classes are known as
concrete classes. Lets make our Vehicle
class abstract.
package info.java8;
/*
A Vehicle Class
*/
public abstract class Vehicle { // Add the abstract keyword to the class definition
...
}
We already have a TestVehicle
class we coded earlier so lets rerun this.
The above screenshot shows the output of testing our abstracted Vehicle
class. The compiler won't allow us to instantiate the Vehicle
class which is exactly what we want.
Time to make our Truck
class abstract as well.
package info.java8;
/*
A Truck Class
*/
public abstract class Truck { // Add the abstract keyword to the class definition
...
}
We already have a TestTruck
class we coded earlier so lets rerun this.
The above screenshot shows the output of testing our abstracted Truck
class. The compiler won't allow us to instantiate the Truck
class which is exactly what we want.
Abstract Methods Top
We can also mark methods as abstract and if we do so the class must also be marked as abstract, as we can't have any abstraction in a concrete class. Whereas an abstract class must
be extended in a subclass, an abstract method must be implemented in the first concrete subclass. This provides a contract that the compiler makes sure is met in the first
concrete subclass. But why is this useful to us? Well it ensures that the first concrete subclass keeps to the contract by implementing any abstract methods of the superclass. To get to grips
with this we need an example. We will code a new Truck
subclass called Tanker
.
package info.java8;
/*
A Tanker Class
*/
public class Tanker extends Truck {
}
Save and compile our Tanker
subclass in directory c:\_OOConcepts in the usual way.
Lets test the new Tanker
subclass to make sure it works:
package info.java8;
/*
Test Class for Tanker
*/
public class TestTanker {
public static void main (String[] args) {
Tanker tanker = new Tanker();
tanker.setChassis("8-axle chassis");
tanker.setMotor("16 stroke");
tanker.setWheels(10);
System.out.println("Our Tanker has a " + tanker.getChassis() + ", " + tanker.getMotor()
+ " motor and has " + tanker.getWheels() + " wheels.");
tanker.service(3);
tanker.carry(2);
tanker.load("10,00 gallons of diesel");
}
}
The above screenshot shows the output of testing our Tanker
subclass. If you look closely at the output we have a problem with the load()
method, it is using the load()
method
from the Vehicle
class. We don't really want this, we want our Tanker
class to override the load()
method like all subclasses of the Truck
class do. So how to do
this? Well we use method abstraction to ensure the first concrete subclass of our Truck
class implements the abstracted method. To see this in action we will add an abstract
load()
method to our Truck
abstract class:
package info.java8;
/*
A Truck Class
*/
public abstract class Truck extends Vehicle {
/*
Our carry() override method
*/
public void carry(int tonnage) {
System.out.println("Our truck can carry up to " + tonnage + " tons of cargo.");
}
/*
Our abstract load() method
*/
public abstract void load(String payload);
}
Well the code for our abstract load()
method certainly looks different! Abstract methods have no body and are terminated by a semicolon.
We should rerun a subclass test to make sure everything is still hunky dory. So recompile Classes HGV
and TestHGV
and run the latter just to make sure everything still works:.
The above screenshot shows the output of testing our HGV
subclass. The class still works as intended. For our purposes we have already overridden the load()
method in the HGV
subclass and thats what implementing an abstract method is, it's the same as overriding a method from a concrete superclass. This also means the same rules apply as those for overriding method rules
Lets see what happens if we don't implement an abstract method, by trying to recompile our new Tanker
class:
package info.java8;
/*
A Tanker Class
*/
public class Tanker extends Truck {
}
As you can see from the screenshot we get a compiler error because we didn't implement the abstract load()
method from the Truck
superclass. Now we are assured that any concrete subclass of
the Truck
class implements the abstract load()
method.
Related Quiz
OO Concepts Quiz 8 - Abstraction
Lesson 8 Complete
In this lesson we continued our investigation of OO concepts by looking at abstraction.
What's Next?
We continue our investigation of OO concepts by learning about polymorphism.