Lecture 12: Extending Classes: Overriding & Shadowing.
A class gives us a description, a list of features that an object of that class should have. By features we mean what kind of data members and method members it should have.
By extending a class we extend our original description, and specify additional features. An object of the extended class has all the features listed in the original class and the class that extends it. An object of the original class has the features listed in the original class.
This is the reason for which we say that if class B
extends
class A
every object of type B
is also an object
of type A
but an object of type A
is not of type
B
(objects of type B
have additional features,
listed in the description of class B
).
Another way to remember this is in this way: if Child
extends
Parent
we can use an object of type Child
everywhere
we can use a Parent
but not the other way around.
This is one kind of polymorphism.
In our discussion in class we have distinguished between:
Objects are anonymous, and we refer to them by names (or object references).
Extending classes is a very simple concept.
Creating composite objects from composite descriptions is as easy as putting the two descriptions together, unless we use the same names for different features (class members of the same kind: data, methods) in the two descriptions.
1. Overriding of Methods. Dynamic Binding (Dynamic Method Lookup)
Consider this:
Essentially we have:class A { void fun() { System.out.println("This is fun as defined in class A."); } } class B extends A { void fun() { System.out.println("This is fun as defined in class B."); } } public class One { public static void main(String[] args) { System.out.println("Welcome to Program One."); A m = new B(); m.fun(); B n = new B(); n.fun(); ((A)n).fun(); } }
![]() |
You see then, that it's the type of the object (and not that of its reference) that really matters.tucotuco.cs.indiana.edu% javac One.java tucotuco.cs.indiana.edu% java One Welcome to Program One. This is fun as defined in class B. This is fun as defined in class B. This is fun as defined in class B. tucotuco.cs.indiana.edu%
If either A
or B
do not define fun()
then there's no overriding involved and no dynamic method lookup is involved.
But it is instructive to cover the three alternatives to the situation
described above:
To summarize, looking up for a method to invoke involves taking into account the class of the object and the class of its reference (casting included here). The object reference's class determine the method unless the object's class also defines a method with the same name, in which case that's the one that will be invoked.
- 1.
A
does not definefun()
- Only objects of type
B
referenced through object references of typeB
will be able to invokefun()
. Casting an object of typeB
to typeA
and asking forfun()
will get you into trouble early (as early as compile time).
- 2.
B
does not definefun()
- Objects of type
b
inheritfun()
fromA
.
- 3. Neither
A
orB
definefun()
- In that case there's nothing to talk about.
Here's another example:
This produces:class A { void fun() { System.out.println("This is fun defined in A."); } } class B extends A { } class C extends B { void fun() { System.out.println("This is fun defined in C."); } } public class Four { public static void main(String[] args) { System.out.println("Welcome to Program Four"); B m = new B(); m.fun(); // fun inherited (A) C n = new C(); n.fun(); // C has its own fun B p = new C(); p.fun(); // Type C overrides the fun // that B inherited from A A q = new C(); q.fun(); // the fun defined in C is used // over the one defined in A, since // the type of the object q points // to (that class) has own fun } }
Once you override a function the only way you can get to it is through atucotuco.cs.indiana.edu% javac Four.java tucotuco.cs.indiana.edu% java Four Welcome to Program Four This is fun defined in A. This is fun defined in C. This is fun defined in C. This is fun defined in C.
super
reference. You can't get to it from outside the class (through casting).
2. Shadowing of Variables
Overriding is a stronger notion than shadowing.
If you shadow a variable you can still get to it from outside by casting.
Here's the example:
Can you annotate this program and tell what's doing?public class Five { public static void main(String[] args) { B m = new B(); m.fun(); m.x = 3; ((A)m).x = 6; m.fun(); } } class A { int x; } class B extends A { int x; void fun() { System.out.println(x + " " + super.x); } }
Two final points:
super
is a kind of casting.
this
is a reference to the current object. The type's
reference is the same as the object's class.