Quantcast

P^i

Your Online Tech Magazine

Tue05212013

Last update04:23:48 AM

Back You are here: Home More Programming and Web Programming Java Guide: Overriding / Overloading

Java Guide: Overriding / Overloading



 

Java - Overriding / Overloading

Overridden Methods

 

Any time you have a class that inherits a method from a superclass, you have the opportunity to override the method (unless, as you learned earlier, the method is marked final). The key benefit of overriding is the ability to define behavior that's specific to a particular subclass type. The following example demonstrates a Horse subclass of Animal overriding the Animal version of the eat() method:
public class Animal {
public void eat() {
System.out.println("Generic Animal Eating Generically");
}
}
class Horse extends Animal {
public void eat() {
System.out.println("Horse eating hay, oats, "
+ "and horse treats");
}
}
For abstract methods you inherit from a superclass, you have no choice. You must implement the method in the subclass unless the subclass is also abstract. Abstract methods must be implemented by the concrete subclass, but this is a lot like saying that the concrete subclass overrides the abstract methods of the superclass. So you could think of abstract methods as methods you're forced to override.
The Animal class creator might have decided that for the purposes of polymorphism, all Animal subtypes should have an eat() method defined in a
unique, specific way. Polymorphically, when someone has an Animal reference that refers not to an Animal instance, but to an Animal subclass instance, the caller should be able to invoke eat() on the Animal reference, but the actual runtime object (say, a Horse instance) will run its own specific eat() method. Marking the eat() method abstract is the Animal programmer's way of saying to all subclass developers, "It doesn't make any sense for your new subtype to use a generic eat() method, so you have to come up with your own eat() method implementation!" A (non-abstract), example of using polymorphism looks like this:
public class TestAnimals {
public static void main (String [] args) {
Animal a = new Animal();
Animal b = new Horse(); //Animal ref, but a Horse object
a.eat(); // Runs the Animal version of eat()
b.eat(); // Runs the Horse version of eat()
}
}
class Animal {
public void eat() {
System.out.println("Generic Animal Eating Generically");
}
}
class Horse extends Animal {
public void eat() {
System.out.println("Horse eating hay, oats, "
+ "and horse treats");
}
public void buck() { }
}
In the preceding code, the test class uses an Animal reference to invoke a method on a Horse object. Remember, the compiler will allow only methods in class Animal to be invoked when using a reference to an Animal. The following would not be legal given the preceding code:
Animal c = new Horse();
c.buck(); // Can't invoke buck();
// Animal class doesn't have that method

To reiterate, the compiler looks only at the reference type, not the instance type. Polymorphism lets you use a more abstract supertype (including an interface) reference to refer to one of its subtypes (including interface implementers).


The overriding method cannot have a more restrictive access modifier than the method being overridden (for example, you can't override a method marked public and make it protected). Think about it: if the Animal class advertises a public eat() method and someone has an Animal reference (in other words, a reference declared as type Animal), that someone will assume it's safe to call eat() on the Animal reference regardless of the actual instance that the Animal reference is referring to. If a subclass were allowed to sneak in and change the access modifier on the overriding method, then suddenly at runtime—when the JVM invokes the true object's (Horse) version of the method rather than the reference type's (Animal) version—the program would die a horrible death. (Not to mention the emotional distress for the one who was betrayed by the rogue subclass.) Let's modify the
polymorphic example we saw earlier in this section.
public class TestAnimals {
public static void main (String [] args) {
Animal a = new Animal();
Animal b = new Horse(); //Animal ref, but a Horse object
a.eat(); // Runs the Animal version of eat()
b.eat(); // Runs the Horse version of eat()
}
}
class Animal {
public void eat() {
System.out.println("Generic Animal Eating Generically");
}
}
class Horse extends Animal {
private void eat() { // whoa! - it's private!
System.out.println("Horse eating hay, oats, "
+ "and horse treats");
}
}
If this code compiled (which it doesn't), the following would fail at runtime:
Animal b = new Horse(); // Animal ref, but a Horse
// object , so far so good
b.eat(); // Meltdown at runtime!

The variable b is of type Animal, which has a public eat() method. But remember that at runtime, Java uses virtual method invocation to dynamically
select the actual version of the method that will run, based on the actual instance. An Animal reference can always refer to a Horse instance, because Horse IS-A(n) Animal. What makes that superclass reference to a subclass instance possible is that the subclass is guaranteed to be able to do everything the superclass can do. Whether the Horse instance overrides the inherited methods of Animal or simply inherits them, anyone with an Animal reference to a Horse instance is free to call all accessible Animal methods. For that reason, an overriding method must fulfill the contract of the superclass.
The rules for overriding a method are as follows:

  • The argument list must exactly match that of the overridden method. If they don't match, you can end up with an overloaded method you didn't intend.
  • The return type must be the same as, or a subtype of, the return type declared in the original overridden method in the superclass. (More on this in a few pages when we discuss covariant returns.)
  • The access level can't be more restrictive than the overridden method's.
  • The access level CAN be less restrictive than that of the overridden method.
  • Instance methods can be overridden only if they are inherited by the subclass. A subclass within the same package as the instance's superclass can override any superclass method that is not marked private or final. A subclass in a different package can override only those non-final methods marked public or protected (since protected methods are inherited by the subclass).
  • The overriding method CAN throw any unchecked (runtime) exception, regardless of whether the overridden method declares the exception.
  • he overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method. For example, a method that declares a FileNotFoundException cannot be overridden by a method that declares a SQLException, Exception, or any other non-runtime exception unless it's a subclass of FileNotFoundException.
  • The overriding method can throw narrower or fewer exceptions. Just because an overridden method "takes risks" doesn't mean that the overriding subclass'
    exception takes the same risks. Bottom line: an overriding method doesn't have to declare any exceptions that it will never throw, regardless of what the overridden method declares.
  • You cannot override a method marked final.
  • You cannot override a method marked static. We'll look at an example in a few pages when we discuss static methods in more detail.
  • If a method can't be inherited, you cannot override it. Remember that overriding implies that you're reimplementing a method you inherited! For example, the following code is not legal, and even if you added an eat() method to Horse, it wouldn't be an override of Animal's eat() method.

public class TestAnimals {

public static void main (String [] args) {

Horse h = new Horse();

h.eat();

 

 

// Not legal because Horse didn't inherit eat()

}

}

class Animal {

private void eat() {

System.out.println("Generic Animal Eating Generically");

}

}

 

 

class Horse extends Animal { }








blog comments powered by Disqus