Inheritance
& Polymorphism
Peter
Komisar © Conestoga College latest version 5.8
Sept / 2010
Inheritance
In this note we talk
about inheritance. We have seen that
'encapsulation' describes the
idea of enclosing a set of
related elements into a class
structure. This structure is
then used to create objects of that
class. Inheritance takes
the idea a step further by allowing new
classes to be built
as extensions of pre-existing class
definitions. Because
a subclass extends the definition of a
parent class,
inheritance is also called extension.
//
inheritance is also referred to as extension
Let us preview the extension mechanism with an example.
It's the 'extends' keyword that is used to create a class that
inherits the attributes of a parent class.
class
Parent extends Child
The Root Object
In Java, only the
root
class, 'Object' has no parent. We have
created many classes in
our examples and we don't usually
include an explicit 'extends' clause.
This is because the
compiler supplies the Object class
extension implicitly.
In a human sense,
inheritance might imply an extension
through time. The only 'time' aspect there is to Java
inheritance is a parent class has to exist before a child
class
can be built on it.
//
all classes are implicit descendants of 'Object class
Java's Inheritance Mechanism
For
all the fanfare, the actual inheritance technique is
simple as was shown above. If a class
Soldier is to be
subclassed
to create a class called
DemolitionExpert
an 'extends' class is included after the class name
indicating that this
new class is a
subclass of the stated
parent class.
Example
class DemolitionExpert extends Soldier { // add specializations }
Let's
create a more elaborate example. If you want a
bilingual
button, in Java you don't have to re-invent the
button. In
object-oriented languages like Java, you can
inherit the
attributes of an existing button and then go
on to add your own
features. The BilingualButton class
defined below extends the
parent class to create an
entirely new class.
This extension was
accomplished with just a few lines
of code yet inherits hundreds of lines of code from it's
parent.
Inheritance Makes Parent (non-private)
Members Available
Notice also by
simply extending a
parent how the parent's
class members become readily available. This is evident
in
the following code example where the setText( ) method is
called
without having had to define it in the class.
Example
import javax.swing.*;
class
BilingualButton
extends
JButton{
BilingualButton(String english, String french){
setText(english + " / " + french);
}
} // calls setText() which it inherits from
JButton
//
a class with a main method to run and show the new button
class bT{
public static void
main(String[] args){
JFrame jf=new
JFrame();
jf.getContentPane().add(new
BilingualButton("dog","chien"));
jf.setSize(400,300);
jf.setVisible(true);
}
}
A Subclass
Can Access Non-private Inherited Members
Let
us assume child and parent are in the same package.
A subclass inherits
all
the non-private members of the parent
as if they were defined in the
subclass explicitly. This is not the
case for members that are marked
'private'. The 'private' modifier
effect extends across
inheritance boundaries. This means a
parent can supply certain
utilities to a child class without allowing
the child
to access to specific items in the parent's code.
To describe the
benefit of
this
arrangement in human terms,
a parent's car keys and credit cards may be considered
as
being
private. A child may
benefit from the transportation
and goods the parents resources
may supply without being
permitted to access and control these
resources.
Example
private String creditCard, carKeys;
//
will not be accessible to a child class however a public
// method in the
parent that accesses this value may make
// these resource values available to the
child class
Example
class Parent{
private String carKeys ="miata";
public String houseKeys="townhouse";
Parent( ){
System.out.println
("Being the parent I can
access my " + carKeys);
}
}
class TeenAger extends Parent{
TeenAger( ){
System.out.println
("Being
the teen I have access to " + houseKeys);
/* System.out.println("I
have access to " + carKeys); */
// This class won't compile
while referencing the private
// variable of the parent. Test this by
removing
comments
// from line
containing 'carKeys' and it's associated out
// statement. Compile and read the compiler report
}
}
class InheritanceDemo{
public static void main(String[]args){
new Parent( ); // will show parent
accessing keys
new TeenAger( );
}
}
Output
[peter@localhost Examples]$ java InheritanceDemo
Being the parent I can access my miata
Being the parent I can access my miata
Being the teen I have access to townhouse
Superclass Constructors are Expressed First
Notice the redundancy in the output. When the TeenAger
class is instantiated, it first invokes the parent constructor
resulting in a repeat of the parent's System.out. statement.
The output also demonstrates that the child has no problem
referencing the parent's public variables, even though
the child class did not declare them.
// an extension first calls the
constructor of it's parent
Inheritance leads
to the creation of class hierarchies that
increase in specialization as the inheritance tree grows.
This is
the only logical direction it can go, since all children
inherit
the type of the parent and then go on to add details
and
variations. The child class increases in complexity
relative to the
parent.
//
Inheritance
leads
to
class hierarchies of increasingly
// specialized
classes
Other
Benefits of Inheritance
Beyond providing an
easy
way for programmers to inherit
'instant' code foundations for
their own designs, inheritance
also allows bug-free stability to be
incorporated into a Java
program. The JButton being
extended in the example benefits
from the fixes provided by legions of programmers.
It is
counter-productive to allow ironed-out to be modified.
Inheritance provides a way to
incrementally build on a stable
legacy of code and hide
well-tested work from exposure to
experimentation and the
introduction of new errors.
Inheritance also
provides a good mechanism to ensure that
compatibility with future
language versions is maintained
and that newer versions of
classes do not break compatibility
with old specifications.
Library
Checks
For
Members
Should Include Parent Members
As stated earlier,
this design results in parent, non-private
class members
being accessible to child classes. (Technically,
the exception is a class member with
default access is not
available to child classes defined outside the package that
the parent
is defined in.)
If a parent has a non-private
variable or method, a child class
can invoke it as if it was it's own
even though it doesn't appear
in the child's class definition. This was
exampled above where
the JButton's setText( ) method was called even
though it wasn't
defined in the child class.
By the same token
JButton has parent classes and those
parent's members and methods
are also available for use
in JButton and in our grandchild
class.
This brings up the
practical issue of checking
parent classes
to find what inherited members are available to the
class. If
in the API a method isn't in the parent class, the next
place
to look is in the parent's parent and so on all the way
back
to Object class.)
// Parent members back to
Object are part of what's available to a child class
The " Is a " vs. " Has a " Test
There are a number of
analysis tricks and techniques that may
be used to decide what should be a
class and what should be
a class member.
One simple
technique is the "Is
a, Has a" rule. It is effective for
determining if one class should be a
member of a class of a
subclass of a class or an extension of that class.
Assume you have a
Car class and an ID class
and you want to
determine what relationship they should have with
each other.
You can create the statement, " A car has an ID"
and another
statement, "A car is an ID ". The first one
makes sense. This
tips you off that a Car class will have an object
of the ID class
as a member.
//
this assumes you use a class rather than just a
// variable to describe an ID.
You have a car
class and an ID class.
A car has an ID OR A
car is an ID 'Has
a' is right so let ID be a member of the car
class.
Example 1
class Car{
Car( ){
ID id=new ID ( );
// etc.
}
}
A second example,
consider a mammal class and a dog class.
Applying the test yield the conditions,
" A dog 'has a' mammal "
and a " A dog 'is a' mammal ".
Though "A dog 'has a' mammal",
may be true with
respect to it's dinner, in the way we are looking
at this it this doesn't make sense. "A
dog 'is a' mammal" is the
sense we are looking for. This signals
us that A dog should be a
subclass of the mammal class.
You have a mammal
and dog class: A dog has a
mammal OR a
dog is a
mammal A dog is a mammal so dog
class should extend
mammal.
Example
2
class Dog extends
Mammal {
// etc.
}
Java
Classes Do Not Use Multiple Inheritance
// a class can only extend a single parent class
Notice we have
never
shown a situation where a class inherits
from more than one parent
class. Java might have supported
multiple inheritance
as C++ and other languages do. The price
that has be paid to
support of multiple inheritance is added
complication.
Extra
rules and referencing techniques have to be supplied
to distinguish
inherited members that have the same name
in both parents. Java
simplifies this situation by using a single
inheritance model.
Each class can only inherit from one parent.
Interfaces
Replace
Multiple Inheritance in Java
In place of
multiple
inheritance, Java provides the interface. A
class can only be
defined as extending a single parent but it can
implement as many
interfaces as needed. In the next example,
the class extends one
class, Frame. It also implements the
interfaces
Runnable. The run( ) method is defined in the
Runnable interface. It is the duty of the class that implements an
interface to supply implementations for any methods that an
interface it is implementing defines.
Example
import
java.awt.*;
import java.awt.event.*;
class
Multi
extends
Frame
implements
ActionListener,
Runnable{
public void run( ){ }
public
void actionPerformed(ActionEvent ae){
}
}
// later we see an
example showing Java Interfaces may multiply inherit
Variable Masking
Inheritance introduces a unique situation
with respect
to class members. Class
members can be defined
identically in both the parent and
child. With variables
this means the same
type and identifier is used. With
methods identical
signatures are used.
Dealing
with variables first, consider a parent class is
defined and a variable
declared and given a value. A
child of this parent class may now
be created with a
variable that is
declared identically to the one used in
the parent. The question becomes if the child variable
is
referenced which value will it take, the
child's value
or that of the parent. The following code creates this
scenario.
Example
class Parent{
String eyeColor ="brown";
}
//
child class
class Child extends Parent{
String eyeColor = "blue";
}
We can
instantiate
these classes inside the main( ) method
of another class. First the two
classes are instantiated and
then each member is referenced using the
dot operator.
Example
class Traits{
public static void main(String args[]
){
Parent
parent=new Parent( );
Child child=new Child( );
System.out.println
( "The parent's eye color is " +
parent.eyeColor + "." );
System.out.println
( "The child's eye color is " +
child.eyeColor + "." );
}
}
Everything behaves
as
expected. The parents value is
exposed as is the child value. What
about the child's
inherited value for eyes. Where did it go? It didn't go
anywhere. It's value is said to be 'masked' or 'hidden'
by the child
variable. You may now ask how the parent
variable might be exposed
or unmasked.
Unmasking Hidden Variables
There are a few
techniques Java supplies to unmask a
parent variable value from
inside the child class. First,
we can instantiate the child
class to the type of the parent.
Example //
typing to the Parent
Parent child =new
Child( );
This will expose
the parent
value for the variable. This
shows that the value of variables is associated
with the
static
type
template that defines the parent class.
Another way to
effect
the same thing is to use the keyword
'super' to reference the parent data
structure.
Example
//
using super
String supersEyes=super.eyes;
Finally the child
type can be cast to the parent type to
expose the parent value. The
extra brackets are being
used to make explicitly clear that the cast
is done before
the variable is
accessed.
Example // casting the reference to Parent type
String castEyes=((Parent)c).n;
We
can collect these techniques and add them to the
Child class we
defined earlier to show their use.
All will
expose the parent value for eyeColor.
Code Sample
class
Parent{
String eyeColor ="hazel";
}
// child class
class Child extends Parent{
String storeSuper=super.eyeColor;
}
class
Traits{
public static void main(String args[] ){
Parent parent=new Parent( );
Child child=new Child( );
Parent childToParent=new Child( );
System.out.println( "\n" + "Accessing Masked Parent
Variable Values:" + "\n");
System.out.println
("- via parent typing of child:
" + childToParent.eyeColor);
System.out.println
("- via a super reference to parent: " +
child.storeSuper);
System.out.println
("- via casting child to parent type: " +
((Parent)child).eyeColor);
}
}
Assignment and Casting Reference Types
Example
of a Cast With Primitive Types
The following
section explains the key ideas in assigning
and casting reference
types. Before proceeding with the
issue of reference type
casting, we can refresh our memory
in how casting is used with
primitive types.
Widening
Assignments
Are Always Acceptable
Recall that it is
always acceptable to make a widening
assignment. We can always assign a byte value to an
int and be sure our value is stored
correctly.
Example
byte
small = 28;
int big = small; // always legal
Also remember that
casting
can
be used with primitive types
to force a narrowing conversion. In
the following example we
create a number that is way too big for an
int type to hold.
Java can force the truncated value to be stored in
an int even
though the number that is stored is relatively
meaningless.
Narrowing
Assignments
Can
be Done By Casting
//
but
meaningless
values may result
class Force{
public static void main(String[]args){
long bigNumber =
10000000000L;
//
ten billion
int truncatedValue = (int)bigNumber;
System.out.println
("\n" + "Only the lower digits of " + bigNumber + "
are stored in the int cast.\n"
+ "The
somewhat meaningless truncated value is " + truncatedValue + "."
);
}
}
// relatively
meaningless value arises from the truncation due to cast
// note, it
might be a meaningful value if the truncation was what was sought!
Some Casts Are Illegal
Finally there are
some cross assignments which are not
legal. In Java you can't cast a boolean to any other type.
Example
boolean boo = true;
int
number =(int) boo;
//
will not compile whether assigned or
cast
Assigning
and
Casting Reference Types
Now let us consider
assigning and casting reference types.
We do this in a number of ways. First we use a description
comparing reference assignment to primitive assignment.
Then we generate a set of rules. Next the rules are shown
in code examples. Finally we do a diagram
summary.
Assignment and
casting of primitive and reference types
have some similarities. These parallel exists due
to the
relationship classes share through inheritance. Where with
primitives, widening assignments are always legal, similarly,
with
reference types a more specialized subclass can always
be assigned to
a more general Parent. We get an inclination
of this should we
create a class and type it to Object type as
in the following
example.
Example
Object o;
JLabel label=new JLabel( );
o=label; //
this is ok and will compile and run!
// with both primitives and reference types widening
assignments
// are always legal
The reason this is
OK is
that a subclass can always be
assigned the type of a more general
parent. Recall that
JLabel in addition to many other types that it
represents
can satisfy the type set of Object, that is, the
collection
of methods defined in Object class. This is similar to
a widening assignment with primitives.
Like with
primitives, where a narrowing conversion is
not assignable, a cast
can be used to force the fit, even
if the result is the storage of a
meaningless number. In
reference types, a parent type can't be
assigned to a
child type. The compiler will not permit it.
However, a
parent can always be cast to a child type to get by
the
compiler.
Example
JLabel label;
Object object=new Object( );
label= (JLabel)object;
//
will compile with the cast but not otherwise
// a cautionary
note: When an object is restricted to the type of a
parent
// only the parent
type methods and variables will be available. The child
// members are not part
of the parent type definition
What Might Compile Might Still Not Run
Although a cast can
be
used to force a compile, a second
hurdle exists with reference types, that of execution at runtime.
Code in casted form may or may not run.
In the final
analysis the object that
has been cast has to
be the same type as the receiving reference
or a subclass
of it. This is similar to the situation with
primitives where
the cast may or not be meaningful. In the case
of reference
types, If at runtime the cast is found to be meaningless
and
as such illegal the runtime will throw a ClassCastException.
//
illegal casts show at runtime as ClassCastExceptions
In the comparison
of primitive and reference type casting
parallels fall apart. While a primitive meaningless cast is
tolerated , the reference cast that is equivalent to
meaningless,
or more specifically is illegal, is not tolerated
and causes
an exception to be thrown.
// a
primitive meaningless cast is tolerated but an illegal reference
// cast is not tolerated, reflected
in the throwing of an exception.
The final part of
the
analogy refers to actions that are plainly
not
allowed. For instance boolean type cannot be assigned
or cast to
any of the other primitive types. A similar situation
exists with
reference types in that in no case can cross
hierarchical
assignments or casts be made. For instance a
Vector object can never
be assigned or cast to a JLabel
reference or visa versa.
What we have just
described is summarized in the following
rules.
Summary of Rules Governing Casting and Assigning Reference Types
1) A
child
object
can always be assigned to a parent reference.
// parent = child;
2)
A parent cast to a child type will compile but may not run.
//
child=(child)parent;
3) At runtime the cast
must be legal, legal meaning the object being
cast must be the same type or a subtype of the receiving reference.
A
ClassCastException will be thrown if
this is not the case.
4) You
cannot cross cast between unrelated
classes
5) Every type inherits from, therefore can be cast to
Object
//
instanceof checks if a reference (on the left-hand side), is an
// instance, (class or sub-class), of a given type (on the right-hand
// side) there instanceof can check
to see if a cast is legal.
Assigning and
Casting Arrays and Interfaces
What we are
covering
here is not the whole story. Arrays and
interfaces represent
other sets of objects that are governed by
rules of assignment and
casting. Generally arrays and interfaces
are very
limited in how they can be assigned or cast. For instance,
both arrays and interfaces can been assigned or cast to Object type.
The story becomes
overly complicated for a first pass dealing with
arrays and interfaces so they are left out of this discussion. You can
investigate assigning and casting these data types at a later time.
Object Casting
Example
Following
is a collection of classes whose objects are assigned
in various ways
to test the rules summarized above.
( Undo the
comments to test each scenario.)
Assignment and Casting Example
class FlyingMachine{ }
class Jet extends
FlyingMachine{ }
class Balloon extends
FlyingMachine { }
class Air{
public
static void main(String[]args){
FlyingMachine
saucer=new FlyingMachine( );
Jet F16=new Jet(
); // child one
Balloon zep = new Balloon( ); //
child two
/*
1. The following compiles and runs as a child is assigned to a
parent*/
// saucer=F16;
/*
2 The next statement doesn't compile. Cross assignment of
incompatible types*/
// F16 = zep;
/*3 Casting doesn't
help. The types are inconvertible*/
//
F16 =(Jet) zep;
/*4
Doesn't compile. Can't assign parent to child */
// F16 = saucer;
/*
5 Compiles but may not run, depending if the cast is legal. */
// F16 = (Jet)saucer;
/*
Legal means the object assigned must be the type of the receiving
reference or a subclass */
}
}
Finally we
summarize in the following diagram.
Quick
Inheritance Assignment Summary
P (parent)
// 1) assigning up is OK , child to
parent
P = A;
____|____
//
2) neither cross assigning or casting are allowed A =/=B;
|
|
//
3) Can't Assign Down, A=/=P, but can cast down, A=(A)P;
(child) A
B (child)
// though at runtime
it be checked to see if it's legal
//
Legal means at runtime the object must the same or a
//
subtype of the type of the reference receiving the object
Polymorphism
The term 'polymorphism' comes
from the Greek meaning
'many shapes'. Although in
programming shapes may be
construed as having an
association with properties, the
common interpretation of
polymorphism in an object-oriented
programming language is associated with behavioural changes
that can be
expressed using methods. Practically, polymorphism
involves using the same
name for a number of methods.
Shallow
Polymorphism
// overloading
'Shallow
polymorphism' is synonymous with method overloading.
Method
overloading involves using the same name for a number
of methods within a class,
distinguishing between them by variations
in their argument lists.
Shallow polymorphism or overloading
can
also be applied to constructors. In the case of overloading,
methods
with the same name behave differently depending on what
arguments are passed to them.
//
shallow polymorphism is method overloading within a class
Deep Polymorphism //
overriding
Deep polymorphism
is
directly related to inheritance. Deep
polymorphism is popularly
known as overriding. A method in a
subclass may perfectly mask a
method defined in a parent, by
supplying the same method with an
identical method signature,
similar to the way variables in a
child class masked the values
attributed to the same variables in
the parent.
//
deep
polymorphism
or
overriding
occurs across inheritance relationships,
// similar to variable masking
Polymorphic
behaviour comes into play when
subclasses provide
different behaviour than the parent for the same
method definition.
Consider an abstract motion( ) method defined for
a generic aquatic
creature. Now consider how differently they
would be exercised in
the implementation that describes the
movement of a jellyfish
compared to a starfish.
Method Overloading // shallow polymorphism
When methods with
the
same names are distinguished by variations
in their argument lists
they are said to be 'overloaded'. The
compiler
distinguishes same-name methods by
variations in the type, order
and number of parameters in a method signature. Return type and
exceptions thrown are not of consequence in overloading.
Overloaded
Signatures are Distinguished by Parameter:
The following example
shows several overloaded forms of a method
called 'measure'.
Examples
// same-name methods with overloaded signatures
public void
measure(int i){ }
public
void measure(int i, int j){ }
//distinguish by # of parameters
public void measure(int i, short j){ }
// "
"
type " "
public void measure(short j, int i){ }
//
"
"
order " "
Another good
example of
overloading is the many print( ) methods
in the
PrintWriter where a different one is defined for each
primitive.
Method Overriding // deep polymorphism
Overriding
describes the
case where a subclass method has an
identical
signature to that of a method in the parent class. This
includes the same method identifier and the same number, type
and
order of parameters. The subclass method effectively overrides
the superclass' variable. Overriding is stricter than
overloading. In
addition to the rules of overloading these
additional restrictions
are applied to overridden methods.
Additional Rules Regarding Overriding
1)
method signatures including return types in overridden methods
must
match
2) Overridden methods cannot
throw new exceptions or exceptions
that are more
general than those of the parent method.
3)
Access modification cannot be more private than in the parent
method,
only
more public.
Overriding
Code
Example
class
Pop{
// a class with a method as member
String getCoffee(){
String black =
"Black thanks";
return black;
}
}
class
Tot
extends
Pop{
//
overrides
getCoffee
String getCoffee( ){
String noThanks = "No thanks";
return noThanks;
}
}
class
Dot
extends
Pop{
// also
overrides getCoffee
String getCoffee( ){
String sugar = "Sugar please";
return sugar;
}
}
class
Host {
public static void main(String[] args){
//
We will declare them all to the general parent type to
// show the parent
type can act as type for subclasses
Pop
pop,tot,dot;
//
caution: typing all the classes to the parent Pop
// type is being done to reveal mechanical aspects
// of the
Java language. In practice you would not
// normally type your classes like this unless there
// was a good reason for doing so
pop =
new
Pop( );
tot = new Tot(
);
dot = new Dot( );
// Here's polymorphism at work. The parent and subclasses
// have the same operations
called but all behaves differently
System.out.println("How
do
you
like
your coffee?");
System.out.println("Pop? " + pop.getCoffee());
System.out.println("Tot? " + tot.getCoffee());
System.out.println("Dot? " + dot.getCoffee());
}
}
Dynamic Binding
Recall how
variables of
objects that had been declared to the
parent type, derived their
values from the parent definition. If
you run the above code you will see
that Java methods are not
influenced by being declared to the type of
the parent. (All the
classes above are typed to the parent class,
Pop.)
Instead methods are
selected based on what type the actual
object being assigned is. So in the above, the overridden
method
of each subclass is expressed. Where the variables
are determined
statically at compile time, the methods
selected are being
determined dynamically at runtime when
the objects are created,
inspected for legality and being
assigned. ( This job is performed
by a special informational
class called 'Class'.)
Self Test Self Test With Answers
1) Which of the
following statements is not correct. In Java inheritance
a) a class can
inherit
from multiple parent classes
b) private variables are not
accessible to a child class
c) extends is the keyword used by a
subclass to extend a parent
d) inheritance provides an easy way
to build on earlier work.
2) Inheritance
assists
development in the following ways. Pick the
incorrect statement.
a) improves eases
of
building on existing work
b) provides protection from entering
bugs into tested code
c) permits maintenance of version
compatibility
d) Provides access to all inherited code and
features.
3) Masked parent
variables values can be revealed by the following.
Pick the incorrect statement.
a)
casting
a
child
variable to the parent type
b) using super to reference the parent object
c) declaring an object to the parent type
d) calling toParent( ) passing in the hidden variable
4) Consider the following classes.
class
Water{ /* H20 */ }
class Mist extends Water{/* air jet over
water */}
class Steam extends Water{ /* boiling
water */ }
class TestWater
{
public static void main(String[]args)
{
Water water;
Mist mist=new Mist( );
Steam steam = new Steam( );
water = new Water( );
steam = (Steam)water;
}
}
This code
a ) won't compile
b ) will compile and run
c ) will
compile but won't run
d ) will
compile and may run
5) Which of the following is not true? With respect for overriding,
a) Overriding
is
related to inheritance
b) Overridden methods may differ in
return type.
c) Overridden methods share the same signature
d) Overridden methods may throw different Exceptions
6 ) Which of the following factors is only significant to one of overloading and overriding?
a) type
b) order
c)
number
d) return type
7)
class
X{
String t="XX";
String getT( ){
String o = "XY";
return o;
}
}
class Y
extends X{
String t="YY";
String getT( ){
String o="YX";
return
o;
}
}
class
XY
{
public static void main(String[]args){
X xy = new Y( );
System.out.println( xy.t + " " + xy.getT( ) );
}
}
a ) XX XY
b)
YY YX
c) XX YX
d) YY XY
8) Select which two of the following methods the compile will not be able to distinguish
a) private void
measure(int i){ }
b) void measure(int i, int j){ }
c)
protected void measure(int i, short j){ }
d) public void
measure(short j){ }
e) void measure(int k, int x) { }
Exercise
//
Please put your name, topic of the lecture associated with the
assignment
// and a number, at the head of the
assignment. ( This is assignment 1. )
// Include the questions and it's
number before your answers where appropriate.
Part I // optional
Here is another
example that demonstrates Java' s built
in overriding behaviour.
Example
class GP
{ int x=1;
void out(){
System.out.println("Grand
Parent Method Version");
}
}
class P extends GP
{
int x=2;
void out(){
System.out.println(" Parent
Method Version");
}
}
class C extends P
{
int x=3;
void out(){
System.out.println("Child
Method Version");
}
}
class GPRun
{
public static void main(String[]args)
{
GP gpc=new C();
System.out.println(gpc.x);
gpc.out();
P pc =new C();
System.out.println(pc.x);
pc.out();
C c =new C();
System.out.println(c.x);
c.out();
}
// typing doesn't unmask overriding
}
OUTPUT
C:\Documents
and Settings\Peter\My Documents\J2\Examples>java GPRun
1
Child Method Version
2
Child Method Version
3
Child Method Version
Questions
1 ) Create a generic parent class that define methods for walking and talking.
2) Create three
subclasses of the generic parent and override the walking and talking
methods so they supply specialized behaviour
for the new classes.
3) In each of the
three
classes create another method, eating sleeping, fishing etc.
Provide overloaded versions of the method that can be used to
demonstrate the
functions use in different
settings. (i.e. eating at home, at a restaurant, by the
campfire etc. )
Part II // hand in, make sure you answer all the
questions
Overloading
public
class Overloading{
public static void
main(String[] args){
int i = 123;
byte j = 127;
Overloading ol= new Overloading();
ol.M(
i , j
);
ol.M( j , i );
}
/**
Here's the two overloaded versions of M method */
void M(int i,
byte
j){
System.out.println(" int i is first, " + i +
" and " + " byte j is next, "+ j);
}
void M(byte j, int i){
System.out.println("
Here byte j is first, " + j + " and " + " int i
is second, "+ i);
}
}
Overloading Question
Q1 Overloaded
methods
are distinguished by the compiler in three ways. Name
the three ways and state which the above two lines of code
demonstrate.
Overriding
class
P{
int Variable=7;
void
M(){System.out.println(" P method version ");
}
}
class C extends P{
int Variable=11;
void M(
){System.out.println(" C method version ");
}
}
class OverRideTest{
public static void main(String[] args){
P pcmix=null;
P p=new P( );
C c=new C( );
pcmix=c;
// assigning child to parent type
p.M( );
c.M( );
pcmix.M( );
System.out.println("
Referencing
parent
object
for
it's variable, Variable is " +
p.Variable);
System.out.println("
Referencing child object for it's variable, Variable is " +
c.Variable);
System.out.println("
Referencing pcmix object for it's variable, Variable is " +
pcmix.Variable);
}
}
Overriding Questions
1)
a) For parent object, p, which value of variable is called(p or c)?
b) For child object, c, which value of
variable is called (p or c)?
c) For child
assigned to parent type variable, pcmix which value
of variable is called (p or c)?
2)
a) For parent object, p, which version of method is called(p or c)?
b) For child object, c, which version of
method is called(p or c?
c) For child assigned
to parent type variable, pcmix which version
of method is called (p or c)?
3)
What conclusion can you draw from these results?