Previous | Table of Contents | Next |
14.3.7.4. Invoking an Overridden Method
Weve seen the important differences between method overriding and variable shadowing. Nevertheless, the Java syntax for invoking an overridden method is very similar to the syntax for accessing a shadowed variable: Both use the super keyword. Example 14.19 illustrates this.
EXAMPLE 14.19. Invoking an overridden method.
class A { int i = 1; int f() { return i; } // A very simple method. } class B extends A { int i; // This variable shadows i in A. int f() { // This method overrides f() in A. i = super.i + 1; // It retrieves A.i this way. return super.f() + i; // And it invokes A.f() this way. } }
Recall that when you use super to refer to a shadowed variable, it is the same as casting this to the superclass type and accessing the variable through that. On the other hand, using super to invoke an overridden method is not the same as casting this. In this case, super has the special purpose of turning off dynamic method lookup and invoking the specific method that the superclass defines or inherits.
In Example 14.19, we use super to invoke an overridden method that is actually defined in the immediate superclass. super also works perfectly well to invoke overridden methods that are defined further up the class hierarchy. This is because the overridden method is inherited by the immediate superclass, and so the super syntax does in fact refer to the correct method.
To make this more concrete, suppose class A defines method f, and that B is a subclass of A, and that C is a subclass of B that overrides method f. Then you can still use:
super.f()
to invoke the overridden method from within class C. This is because class B inherits method f from class A. If classes A, B, and C all define method f, however, then calling super.f() in class C invokes class Bs definition of the method. In this case, there is no way to invoke A.f() from within class C. super.super.f() is not legal Java syntax!
It is important to note that super can only be used to invoke overridden methods from within the class that does the overriding. With our Circle and Ellipse classes, for example, there is no way to write a program (with or without super) that invokes the Circle area() method on an object of type Ellipse. The only way to do this is to use super in a method within the Ellipse class.
Finally, note that this form of super does not have to occur in the first statement in a method, as it does when used to invoke a superclass constructor method.
14.3.7.5. Finalizer Chaining Revisited
Now that weve discussed method overriding and how to invoke an overridden method, we can return to the issue of the finalizer method that we left dangling earlier on.
In Java, constructor methods are automatically chained, but finalizer methods are not. If you define a finalize() method to free resources allocated by your class, you may be overriding a finalize() method in a superclass that frees resources allocated by that class. If your finalizer method does not invoke the superclass finalizer, the superclass finalizer never gets called, and resources are not deallocated when they should be.
To prevent this, you should be sure to invoke the superclass finalize() method. The best time to do this is usually after your finalize() method has done all of its deallocation. It is a good idea to add the following call:
super.finalize();
as the last line of all your finalizer methods. You should do this even if you know that none of your classs superclasses have finalizer methods, because future implementations of the class may include one.
We started this section by describing a class as a collection of data and methods. One of the important object-oriented techniques that we havent discussed so far is hiding the data within the class, and making it available only through the methods. This technique is often known as encapsulation, because it seals the classs data (and internal methods) safely inside the capsule of the class, where it can be accessed only by trusted usersi.e., by the methods of the class.
Why would you want to do this? The most important reason is to hide the internal implementation details of your class. If you prevent programmers from relying on those details, then you can safely modify the implementation without worrying that you will break existing code that uses the class.
Another reason for encapsulation is to protect your class against accidental or willful stupidity. A class often contains a number of variables that are interdependent and must be in a consistent state. If you allow a programmer (this may be you yourself) to manipulate those variables directly, she may change one variable without changing important related variables, thus leaving the class in an inconsistent state. If, instead, she had to call a method to change the variable, that method can be sure to do everything necessary to keep the state consistent.
Heres another way to think about encapsulation: When all of a classs variables are hidden, the classs methods define the only possible operations that can be performed on objects of that class. Once you have carefully tested and debugged your methods, you can be confident that the class will work as expected. On the other hand, if all the variables can be directly manipulated, the number of possibilities you have to test becomes unmanageable.
There are other reasons to hide data, too:
Previous | Table of Contents | Next |