Previously we talked about the idea of inheritance and classes. When Class A inherits from Class B then the instance variables and methods of Class B are available to Class A. This allows us to be more granular in our implementations, for example:
In the above example, we're looking at some simplified classes for a video game. All Characters (the parent class) have a few common attributes such as hit points (hp) and an animation (sprites). They even share a few common methods such as attack or render.
The child classes Player and Enemy have more specific instance variables and methods. The Player, for example has equipped items and the ability to move around the map. Enemies, on the other hand, have weaknesses and loot tables for when they are defeated.
This configuration works to some extent, but sometimes it doesn't make sense to implement a method in the parent class because every child will require a different implementation. For instance, look at the class diagram for the shapes we have been working with:
In this case, it does not make sense for the Shape class to implement the getArea() and getPerimeter() functions since each child class (Rectangle, Triangle and Circle) would need to override it.
This is a perfect example of why abstract classes exist! We create and use abstract classes when one class is the basis for a set of other classes. All child classes share some common implementations, but it does not make sense to implement them all since the details of HOW they are implemented will differ between children.
An abstract class is a class that is partially implemented class: The parts which are common to all child classes will have method bodies. Everything else will be declared abstract and not be implemented. It is important to note that an abstract class cannot be directly instantiated (i.e. you cannot write new Shape("red"); and expect the file to compile.), instead, you must have a child class which implements the missing methods. Only the child classes can be instantiated.
Look carefully at the Shape class in the class diagram:
The class name Shape, is in italics, identifying it as an abstract class. In addition, the getArea() and getPerimeter() method signatures are also in italics. This identifies them as abstract methods which are not implemented in the Shape.java file.
Below is the Java code for the Shape class as it is drawn in our class diagram.
We use the abstract keyword to make a class abstract. All unimplemented methods must also have the abstract keyword in order to mark them to the compiler as abstract.
In our case, the getArea() and getPerimeter() methods are abstact and thus unimplemented, ending with a semicolon (;) instead of a set of curly braces { }.
Before we can use the shape class we need to extend the Shape class and implement getArea and getPerimeter. Below is the code for Circle.java.
A child class can only extend one abstract class. What is meant by this is that the code
public class Child extends ParentA, ParentB
is NOT valid. The Child cannot be both a ParentA or ParentB directly, it can only extend one.
Change the Tile Price Calculator program you created previously to use an abstract class in place of the base Shape class.