Inheritance
& Polymorphism
Peter
Komisar © Conestoga College latest version 5.4 / 2006
Inheritance
In this note we talk
about inheritance. '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 already existent class
definitions. Because a subclass
extends the definition of a
parent class, inheritance is also called
extension.
// inheritance is also referred to as extension
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 not necessary as the compiler supplies the
Object class
extension for us implicitly. Object is the ultimate parent of
all
classes. In a human sense, inheritance implies a sort of
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
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 even across
inheritance boundaries. This means a parent
can supply certain
utilities to a child class without offering the child
explicit access to these aspects of the parent 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 by removing
comments from line
containing 'carKeys'
// variable compile and read the
compiler report
}
}
class InheritanceDemo{
public static void main(String[]args){
new Parent( ); // will show parent
accessing keys
new TeenAger( );
}
}
The output shows that when the TeenAger class instantiates
it's parent constructor is invoked first. Also note that this example
demonstrates
that non-private variables are automatically inherited
and available for use
in the child.
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
Another aspect that
derives from inheritance is 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.
How to inherit
For
all the fanfare, the actual inheritance technique is simple. We
already
have had
previews of what is involved. If a class Soldier
was 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 thousands
of lines of code from it's parent. Notice also by
simply extending a
parent how it's class members become 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);
}
}
//
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);
}
}
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 thousands
of hours of exhaustive use by
thousands of programmers. Bugs
will have been ironed out and
fixed. The widget you will use is
most probably bug-free. When you
debug code based on these
components, you will look in the new
code for problems not the
old. 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.
//
The inheritance mechanism allows 'ironed out' code to be hidden
// while still permitting extension and experimentation to continue.
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.
//
inheritance as an organizational technique simplifies maintenance
// of
backward compatibility
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.)
// The Inheritance model
requires that we are aware of functions and
// variables that are available to a class through inheritance.
Practically,
// if we were checking the
documentation for a class for a method to
// do something, we should also check the parent
specification to see
// what methods it supplies
The " Is a " vs. " Has a " Test
There are a number of
analysis tricks and techniques used to decide
what should be a
class and what should be a class member. One of
the simplest and most
effective techniques for determining if one
class should be a
member of a class of a subclass of a class is to
use the "Is
a, Has a" rule.
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.
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 yields,
" 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 most cases 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
doesn't multiple inherit
// 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 been designed
to support 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.
In place of
multiple
inheritance, Java provides the interface. A
class can only be
defined as extending a single class but it can
implement as many
interfaces as it wants. The following class
skeleton extends one
class, Frame and implements two interfaces,
ActionListener and
Runnable. Notice two stub methods are
provided. They are the
methods the two interfaces define. When
a class implements an
interface it takes on the responsibility of
implementing the
interface methods.
Example
import
java.awt.*;
import java.awt.event.*;
class
Multi
extends Frame implements ActionListener, Runnable{
public void run( ){ }
public
void actionPerformed(ActionEvent ae){
}
}
Variable Masking
Speaking
on the issue of inherited members, there is a unique
situation that
arises with inheritance. 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, a parent class may be 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. We can clarify this
situation using an example.
Example
class Parent{
String eyeColor ="brown";
}
//
child class
class Child extends Parent{
String eyeColor = "blue";
}
Now we can
instantiate
these classes in another class with a
main( ) method. 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 and
the child value. What
about child' 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 that can be used to unmask the parent
variable value from
inside the child class. First, we can instantiate
the child
class to the type of the parent. 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.
Example
Parent child =new
Child( ); //
typing to the Parent
Another way to
effect
the same thing is to use the keyword
'super' to reference the parent data
structure.
Example
String supersEyes=super.eyes; // using super
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
String castEyes=((Parent)c).n;
//
casting the reference to Parent type
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.
Recall that it is
always acceptable to make a widening assignment.
We can always assign an 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 to hold. Java can force the truncated value
to be stored in
an int even though the number that is stored is relatively
meaningless.
Finally there are
some cross assignments which are not legal.
Example
boolean boo = true;
int
number =(int) boo;
// will not compile whether assigned or cast
Example
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
meaningless truncated value is " + truncatedValue + "." );
}
}
Assigning
and Casting Reference Types
We cover the ideas
involved in assigning and casting reference
types from four
different angles. First in a descriptive narrative,
then in a
rules summary, followed by a code example and finally
a diagram
summary. Although redundant, the information is all
complimentary and is useful to repeat in different contexts.
Assignment and
casting of primitive types and the assignment
and casting of
references have some analogies. The 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
when 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!
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.
Again, comparing to
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 minor
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
Although a cast can
be
used to force a compile, the second hurdle
that needs to be crossed
is whether the code will 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 the runtime finds the cast was
not meaningful
and as such illegal, a ClassCastException will be
thrown.
There is really
different behaviour in this case between the
primitive
and reference type. While the primitive will tolerate a
meaningless
cast, the reference cast that is equivalent to
meaningless, or more
specifically is illegal, is not tolerated
and causes an exception to
be thrown.
The final part of
the
analogy refers to situations with primitives 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 hierarchal
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.
What we are covering
here is not really the whole story. Arrays
and interfaces represent
other sets of objects that are governed
by rules of assignment and
casting. Generally the rules that apply
to arrays and interfaces are very
limited.
In my opinion they
make the story overly complicated for
the first
pass. We leave them out of our discussion. After you get onto the
general ideas of
assignment and casting with class types you can
investigate
how the same ideas apply to array and interface types
on your own. )
Following
is a collection of classes whose objects are assigned
in various ways
to test the rules summarized above.
( Undo the
comments if you wish to 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 */
}
}
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
Polymorphism comes
from Greek and means 'many shapes'.
Although in
programming shapes may be construed as having
an
association with properties, the common interpretation of
polymorphism is associated with behavioural changes that can
be
expressed using methods. Polymorphism involves using
the same
name for a number of methods.
Shallow
Polymorphism
// overloading
There is 'shallow
polymorphism' that is synonymous with method
overloading. Method
overloading is using the same name for a
number of methods,
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.
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.
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 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
// different 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 " "
/*
adding
public String measure(short j, int i) throws Exception{ //stuff }
would
not be distinguishable from the previous method example
*/
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'.
The principles of
Inheritance and Polymorphism along with
Abstraction and
Encapsulation are the four principle pillars of
object-oriented
systems. They work in object-oriented languages
together to
create systems of complex and interconnected object
that have
been successfully applied to supply a great number
of successful
solutions to real-world programming problems.
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
Part I 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
Overloading
Exercise
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
Exercise
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?