|Java Class Inheritance|
|Written by Ian Elliot|
Page 2 of 4
When you first create an instance of an object there is often the need to initialize it before using it. The obvious thing to do is to write an “init” member function and remember to call this before going on.
The trouble with this idea is that you could forget to use init before getting on with the rest of the program. To help avoid this Java and most other object oriented languages use special functions called constructors that can be used to automatically initialize a class.
A constructor has to have the same name as the class and it is called when you create a new object of the class. For example, if we add the constructor
to the point class you can create and initialize a new object using
Notice the way that the values to be used in the initialization are specified. In fact you can think about the use of Point(10,20) as being a call to the constructor.
As well as an initialization routine, you can also specify a clean up routine called finalize() that is called whenever an object is about to be deleted. This isn’t used as much as the constructor but it is still handy.
If you don’t bother to write a constructor the Java system provides a default constructor that does nothing and takes no parameters.
If you define a constructor of any sort the system doesn’t provide a default. So if you define a constructor that takes parameters, e.g. point(x,y), don’t forget to also define a parameter-less constructor, i.e. point(), if you also want to create objects without any initialization or with a default initialization.
It is worth knowing at this early stage that the whole subject of initializing objects is a complicated one that has lots of different clever solutions.
For the moment knowing about constructors is probably enough.
The previous section introduces a new idea. You can define any number of constructors as long as each one has a different set of parameters. This means you have functions i.e. the constructors all with the same name, the name of the class, differing only by the parameters used to call them. This is an example of overloading.
Although it doesn’t actually have anything directly to do with object oriented programming, and so rightly should be left until some other time, overloading is too useful to postpone.
The general idea is that you can have any number of functions with the same name as long as they can be distinguished by the parameters you use to call the function.
In more formal terms the “signature” of a function is the pattern of data types used to call it. For example,
has a signature int,int and
has the signature float,float, and
has the signature int,float and so on…
When you call a function for which there is more than one definition the signature is used to sort out which one you mean.
In this sense you can consider that the name of a function is not just the name that you call it by but its name and types of parameters. So Swap is really Swapintint, Swapfloatfloat and Swapintfloat and so non. But notice that this is just a handy way to think about things you can't actually use these names.
For example, given the multiple “overloaded” definitions of Swap given earlier, the call Swap(x,y) where x and y are ints would call the first Swap, i.e. the one with signature int,int. As long as the function used can be matched up with definition with the same signature everything will work.
What function overloading allows you to do is create what looks like a single function that works appropriately with a wide range of different types of data.
You can even define functions with the same name that have different numbers of parameters. For example, Swap(int a, int b, int c) has a signature int,int,int and thus is a valid overloaded form of Swap.
As already mentioned of the most common uses of overloading is to provide a number of different class constructors. For example, you could create a point(int a) constructor which only initializes the x data member or the point(float r, float t) constructor which sets x and y from a radius and an angle.
Notice a function’s return type is not part of its signature.
A class defines a collection of methods and properties that represents a some sort of logically coherent entity. For example a geometric point. However you soon begin to notice that some types of entity form a family tree of things.
The key thing that should alerts you to this situation is when you find yourself saying an A IS A B with some extra features.
In object oriented terms what this is saying is that the class that represents A is essentially B with some additional methods and properties. Overall an A behaves like a B but it has some extras - it is a bit more than a B.
To accommodate this situation we allow a new class to be derived from an existing class by building on its definition.
For example we have a class that represents a 2D Point and perhaps we want a 2D Point that also specifies a color. Now you could say that PointColor is just a Point with a color property.
In this sense we could say that PointColor extends the idea of a Point and in Java this would be written -
What this means exactly is that the definition of the PointColor class starts off from all of the definitions in the Point class. It is as if you have just cut and pasted all of the text in the Point definition into the PointColor definition.
In more technical terms we say that PointColor inherits from Point and this is a specific example of class inheritance.
If you did nothing else at all an instance of the line class would be exactly the same as the point class - it would have setX, setY, getX, getY and so on as members.
In short all of the members of Point are members of PointColor.
What is the good of inheritance?
Well the key lies in the use of the term “extends”. You don’t have to stop with what you have inherited, you can add data and function members to the new class and these are added to what has been inherited.
That is the class that you are extending acts as a basis for your new class - the class you are extending is often called the base class for this reason but the terminology varies. The key idea to get is that when a class extends another it is everything that class is and more.
For example, in the case of the PointColor class we need one more variables to store the color and some get/set methods.
Now the new PointColor class as all of the methods of Point and a new Color property complete with get/set methods. You can use all of the methods of PointColor with no distinction between what is inherited and what newly defined.
Notice that you can't directly access the property variables such as X,Y and Color directly only via the set/get methods. This is also true for the code within PointColor. That is PointColor cannot directly access X and Y, the variables that belong to Point. They are just as much private from PointColor as they are to the rest of the world. PointColor can't get at the internals of Point.
The relationship between PointColor and its base class Point is simple but it can become more complicated. Before classes and inheritance programmers did reuse code by copy and pasting the text of the code. This worked but any changes made to the original code were not passed on to the copied code. With inheritance if you change the base class every class that extends it are also changed in the same way. The inheritance is dynamic and this is both a good and a bad thing. The problem is that changing a base class might break the classes that extend it. It is for this reason that how a base class does its job should be hidden from the classes that extend it so that they cannot make use of something that might well change. This is the reason that extending classes cannot access the private variables and functions of the base class.