Extending a class is simple. In a new class definition, simply add the word extends and the name of the class the new class should extend. This new class is now a subclass of the class which it extends.
In processing and other programming languages there are various tools to help add complexity to a program without requiring the programmer to rewrite a lot of code. In fact, good programming practice should have you never writing the same code twice. Since we are working with objects, sometimes its beneficial to describe objects as more specific versions of some general object.
Take a look at these bikes. There is a general Bicycle object, and then there are a few specific Bicycle objects. Each specific Bicycle object extends the general Bicycle class, and therefore is a subclass of the Bicycle class.
As mentioned previously, the goal of efficient programming is to never repeat yourself. If we find that when creating a new object we're repeating a lot of the fields and methods that belong to another, similar object. We might want to "abstract" out the common properties of both classes, and put these into a parent class. Now each object from before can inherit these common fields and methods, and there's no need to code them for each object.
Take another look at the bikes. Every bicycle needs a position, wheel rotation, gear, etc...
But only a mountain bike would need shock suspension. And perhaps only a race bike would need road tires, or a speedometer.
When designing several classes, always remember that common fields and methods should be combined into a parent class, and each class should extend from that parent. This will save time and create cleaner, more flexible code.
A subclass is simply a class which extends another class. This is called inheritance because the sublclass inherits the fields and methods of the parent class. Let's take a look at the anatomy of a subclass:
Notice how our subclass RaceBike inherits the fields and methods of Bicycle? This means that each new RaceBike object can set the values of xPos, yPos, xVel, yVel, in addition to the new field speedometer (specific to the RaceBike class).
Let's take a look at how we could create an instance of the RaceBike class and use some inherited fields and methods from the Bicycle class:
Scope is the notion that there is a range of code in which a variable is valid. For example, the variable iThing is only known inside the thingy() function. In general, a pair of enclosing braces indicates the scope of a variable.
Super is a special scoped reference variable which can be used to the refer to the scope to the parent class. This means we can use super to refer explicitly to the scope of the parent class. Let's take a look at how we can use super:
Sometimes it may be advantageous for a subclass to call the constructor of its parent class. We can achieve this by using the super( ... ) constructor. Here's an example:
Notice when using super( ... ) we must pass in parameters to match the constructor we are calling. There are two constructors here: one to initialize the bike with a random position, and the other (overloaded) one to initialize it with a specific position. By using super( ... ) with appropriate arguments for each constructor in the subclass RaceBike, we've managed to match parameters and leverage the code that was already written in the Bicycle class constructors.
We can also use super as a special reference variable to call methods of a parent class from within the subclass. Here's an example:
Remember how a subclass inherits all of the fields and methods of a parent class? This means that processing now
considers the subclass to be an equivalent of the parent class. This principle is called polymorphism and we usually say that
an instance of a subclass "is a" instance of the parent class.
In other words: a RaceBike "is a" Bicycle.
Let's see this in action:
Storing a subclass reference using the parent class type is totally legal, however the reverse is not possible. Since a RaceBike "is a" Bicycle, we can use a Bicycle reference variable to store a RaceBike reference, but a Bicycle is not necessarily a RaceBike.
Polymorphism has its advantages, since all Bicycle subclasses can be treated as if they were Bicycles. For instance we can take all Bicycle instances, regardless of type, and store them in a single typed ArrayList since they are all Bicycles.
There is a disadvantage to using the parent type to store a reference of a subclass. The reference variable type is of the parent class, therefore we cannot use this variable to access the fields or methods of the subclass. Let's see an example:
Overriding is similar to overloading, however it involves a subclass implementing a method with the exact same method signature as the parent class. If an instance of the subclass is stored in a reference variable of the parent type, the overridden methods of the subclass will be called instead of the parent's methods. By overriding methods properly we can treat all objects as the parent type, call the same methods, while having different implementations. Here is an example:
Notice how the RaceBike methods have the same method signature as the Bicycle methods. Even if a RaceBike is stored in a reference variable of type Bicycle, when we call the methods of this variable we will in fact be calling the overridden methods from the RaceBike class.
Writing with subclasses requires a bit of planning.
Plan out what your parent and child classes will store and what they can do. Child classes will likely have more kinds of data in them.
Since subclasses can use overridden methods, plan these methods out for super and subclass.