The remaining concepts are somewhat more complicated, but they provide the nuts and bolts of any object-oriented programming language. While it is possible that in tiny programs these concepts are not necessary, they are essential for programming with a graphical user interface.
The true value of inheritance will become clear when we start making extensive uses of
standard Java core classes, especially those contained in the Abstract Window Toolkit
(awt). For now, it is not always obvious why inheritance makes programming more efficient.
However, at the very least it makes for esthetical code that resembles somewhat the true
relationship between objects. Also, inheritance will usually result in a reduced number of
lines of code, as well as in objects that are more likely to work correctly and are easier
to fix if they do not.
Rather than creating different, unrelated classes for each of these objects, we first try to explore whether there is some relationship between them. Actually, the first sentence in the example already indicates that relationship: both rectangle and circles are geometric shapes. Moreover, all geometric shapes have a name, an area, and a perimeter. Therefore, we first design a class Shape that will serve as our superclass. We will declare the class as being public, which implies that it needs to be saved in a file named "Shape.java".
Since we dont know the actual shape, we can not compute appropriate values for the area and perimeter yet. Now, a rectangle and a circle are both more specific shapes. Hence, we want to indicate that relationship when defining these new classes by stating that both circles and rectangles are descendents, or subclasses, or the Shape class. In other words:
Thus, Rectangle and Circle are both defined as subclasses of Shape, and therefore they inherit the fields and methods of that superclass. Note that both fields in Shape do not have an access modifier and are therefore friendly fields. As such, they can be inherited and accessed by the Rectangle and Circle class. Had we designated the area and perimeter fields of Shape as private they would not be inherited by any subclass.
Here is a possible implementation of the Rectangle class:
Note that the Rectangle class can use the name, perimeter and area fields even though it does not explicitly declare them. However, since Rectangle extends Shape, it inherits those fields, and can therefore use them as if they were its own. Since Rectangle is public, we must save it in a file named "Rectangle.java".
Similarly, we can implement the Circle class as follows (recall that the area of a circle is and the circumference, or perimeter, is , where r is the radius):
Since the Rectangle and Circle classes inherit the name, area and perimeter field from Shape, they do not need to explicitly declare those fields again. In fact, if they did declare them again, they would hide the original fields of the Shape class (see below). In addition, all shapes can make use of the display method of the superclass, without having to define it again in each new actual shape.
To test these classes, here is a sample program (to be saved in a file named "ShapeTester.java"):
One of the advantages of inheritance is that it is easy to add new classes.
As before, a Square extends Shape, inheriting its fields and methods:
Actually, another approach seems better: why not say that a square is a special case of a rectangle - which it is, after all. In other words, our new class implementation would start out as:
While that sounds like the right approach, there is a slight problem, but we have no need right now to discuss that. Instead, if you follow the remedies below, you will never see the problem:
|Every class extending another class should always include an explicit call to one of the constructors of its superclass with the appropriate parameters. That call to the superclass constructor must appear as the first line in the subclass constructor.|
|Provide a constructor with no arguments for any classes that may become a superclass. If additional constructors are needed, simply use the concept of overloading to define them as well.|
Now lets return to the previous example of a Square class that extends Rectangle instead of Shape.
The new class will be extremely short, yet it will have the same capabilities as the other subclasses of Shape: