Witscale Test Center

11.3 Method overloading and overriding > 11.3.2 Method overriding


11.3.2 Method overriding

We saw how method names are overloaded and how the method arguments are used to distinguish between the methods with same name. Overloading is essentially a programming technique and has little to do with object-oriented programming. In fact, non object-oriented languages such as C also supports overloading. Overriding on the other hand is a different story.  Overriding is directly related to OOP with inheritance and subclassing.

When you create a subclass of a class, it inherits behavior (non-private methods) of the original class. The subclass can reuse this inherited behavior. However, often it wants to modify some of the inherited behavior to match the specialized behavior it is supposed to implement. You can modify the behavior by redefining the inherited method in the subclass. This redefining is popularly known as the method overriding. The method in the super class is called as the overridden method and the method in the subclass is called as the overriding method.

Why to override?

The need for method overriding can be best understood with an example. Consider a class Camera and its subclass SLRCamera. The Camera class has a shoot() method implementing basic photographing. The subclass SLRCamera is specialized camera needing more adjustments while shooting. Therefore, it is likely to redefine the shooting behavior. Listing 11.1 shows the two classes with the shoot method.

 

 


 

 

The shoot method in Camera is a public method that takes int parameter and returns nothing. The SLRCamera inherits it, but it has a specialized way of shooting. Since it does not want this inherited behavior ( and wants to keep the same method-name), it is overriding the inherited shoot method by declaring its own shoot method with the exact same signature.

Late binding of methods

When you create an object of SLRCamera and call the shoot method on it, the overriding method in SLRCamera class is called. In the following example, myCamera.shoot() will call the SLRCamera’s shoot method at runtime.

 

SLRCamera myCamera = new SLRCamera();

myCamera.shoot();             // calls shoot() defined in SLRCamera

 

Now if you store the SLRCamera object’s reference in the variable of Camera type and call shoot method on it, still the overriding method in SLRCamera class is called. In the following example, an object of SLRCamera is created.

 

Camera camera = new SLRCamera();

camera.shoot();            // calls shoot() defined in SLRCamera

 

The call camera.shoot(); will call the shoot method of SLRCamera even though the variable camera is of Camera type. Java determines the method to be executed based on the type of actual object at runtime. At compile time no object is created yet, hence Java does not predetermine the method to be called at compile time just by looking at  camera.shoot().

The object new SLRCamera(); is created at runtime. Thus Java knows what type of object the variable camera is holding and calls the appropriate method. Thus the method invoked at runtime by camera.shoot() is not based on the variable’s type (Camera in this case), but on object’s type (SLRCamera in this case) at runtime.

 

Note: In most object-oriented languages, the decision of which method to call is delayed to the runtime as the type of actual object (that the reference variable will hold) is often not known at compile time. This particular feature is known as late binding of methods in Java. We will see later in the chapter that the same is not true for member variables.

 

 

Rules of overriding a method

There are certain things you need to make sure while overriding a method correctly –

 

1.       The method must have same method name as the method in the superclass. In addition, the type and order of arguments must be same.

Note if the method name is same and the type & order of its arguments is different, the methods are considered as overloaded and Java compiler will not give you an error. However, the method subclass will not redefining the method in superclass. For example, consider following methods in superclass Camera.

public void shoot(int filmspeed) {       

 // take the picture!

}                                        

boolean changeFilmSpeed(int speed, String unit) {

  // some implementation

  return true;

}

Table shows the examples of shoot methods declared in subclass SLRCamera if Camera class has shoot method as defined in listing 11.1

 

Table 11.1 Overriding method must have same name and arguments as the overridden method

 

Valid Overriding methods

Not-a -overriding method

 

reasons

public void shoot(int filmspeed) {       

   // take the picture!

}                                         

 public void shoot() {       

   // take the picture!

}                                        

 

The shoot method without any argument is not-a-overriding method as it is not taking same arguments as the method in super class. But it is a valid overloaded method in SLRCamera.

 

2.       The overriding method must have same return type as the overridden method.

 

Table 11.2 Overriding method must have same return type as the overridden method

 

Valid Overriding methods

Not-a -overriding method

 

reasons

boolean changeFilmSpeed (int speed, String unit) {

   // some implementation

   return true;

}

void changeFilmSpeed (int speed, String unit) {

   // some implementation

}

This method’s return type is void. It is also not valid as overloading method. It only has its return type different which not sufficient for overloading.

If you are upgrading from SCJP 1.4 to SCJP 5.0, please note that covariant return types are now allowed while overriding. It simply means that the overriding method can either have exactly same or narrower return type as the overridden method. For example, imagine a PhotoOp class that has a method getEquipment with signature public Camera getEquipment();. Now you can override this method (while subclassing the PhotoOp class) to public SLRCamera getEquipment() assuming SLRCamera is a subclass of Camera class.

 

 

3.       You modify the access modifiers in subclass but they must be less restrictive than the original method in super class. 

For example, if the method in superclass has a protected access modifier, you can override it with the public access modifier. The following stick diagram illustrates access modifiers from most restrictive to least restrictive.

 

private ->  default -> protected -> public

 

Since public is the least restrictive, you can override a public method with only a public method. If you try to restrictive modifiers, a compile-time error. Table shows the examples of changeFilmSpeed methods declared in subclass SLRCamera if Camera class has changeFilmSpeed method as defined in listing 11.1. You cannot override the method with a private modifier, the compiler will flag an error saying “Cannot reduce the visibility of the inherited method from Camera”.

 

Table 11.3 Overriding method must not be declared more restrictive than the overridden method

 

Valid Overriding methods

Not-a -overriding method

 

reasons

boolean changeFilmSpeed (int speed, String unit) {

   // some implementation

   return true;

}

 

private boolean changeFilmSpeed (int speed, String unit) {

   // some implementation

return true;

}

This method’s access modifier cannot be private. The method to be overridden has no access modifier. Therefore, it can be overridden with either the default access, protected access or public access.

protected boolean changeFilmSpeed (int speed, String unit) {

   // some implementation

   return true;

}

public boolean changeFilmSpeed (int speed, String unit) {

   // some implementation

   return true;

}

 

This rule is imposed because Java assumes that you do subclassing for extending a class. If Java had allowed you to override a method to be more private, you could have easily made  the public methods of superclass inaccessible (in subclass). Effectively you would have restricted the class instead of extending it. Since in Java subclassing is done only to extend a class, you are not allowed to restrict its behavior by overriding the methods to be more private.

 

Though the rule we studied applies to the private methods defined in super class, these methods are not actually overridden. Note that private methods are not really inherited by the subclasses. So redefining them by overriding has actually no meaning. Since they are private, they are not available to the subclass. Therefore, the subclass can still define a method with same signature as the private method in super class. But it would not be overriding in true sense.

 

4.       The overridden method may not throw any checked exceptions at all. If it throws, the exception must be either same as the exception thrown by the superclass method or the exception must be a subclass of the exception thrown by the superclass method. We have seen the checked exceptions in chapter 5 (See section 5.5.4)

5.       You cannot override a final method of superclass.

Overriding means you want to modify a method whereas declaring a method as final means you want that method unchangeable. These two things are contradicting and hence Java does not allow you to override a final method.

 

 The overriding method (the method in subclass) can be declared as final. In that case, you cannot further override that method.

 

Invoking overridden method using the super

We saw earlier in method overloading how you can call the other overloaded method from a method. While overriding a method, it is sometimes useful to be able to call the overridden method (in superclass). For example, the shoot() method in SLRCamera overrides the shoot() method in Camera. Now if the SLRCamera has some shooting behavior common as the Camera, it must implement it when it is redefining the method. You can see in the listing 11.1 that the SLRCamera needs to re-implement basic shooting behavior (frame and take the picture!) just like Camera. So you will have duplicate code in Camera as well as SLRCamera for implementing the basic shooting behavior. Java provides you an elegant alternative to avoid this duplication of efforts. The SLRCamera can reuse Camera's implementation of shoot method by calling the Camera class’s shoot method from SLRCamera. It can do so with the help of super keyword as super.shoot();

Figure 11.6 illustrates the sequence of events when you call the SLRCamera’s shoot method as new SLRCamera().shoot();



Figure 11. 6 Invoking the overridden method shoot(int) from the overriding method using super

 

The shoot method in SLRCamera first implements the specialized behavior such as adjusting aperture and exposure. After that it calls the shoot method of Camera with super.shoot(filmSpeed); In second step the shoot method of super class is executed. The control returns back to the overriding method in step 3. Thus, you can call the overridden method wherever it suits for reusing the common implementation in subclass.

 

The keyword super is good for going only one level up in the class hierarchy. For example, we can further subclass SLRCamera as DigitalSLRCamera and override the shoot method. But we cannot call the Camera class’s shoot method from it as super.super.shoot(filmSpeed);

 


You also cannot call private methods of superclass with the super keyword. Private features of class are inaccessible to everyone except the class itself.