39
Engr 691 Engr 691 Special Topics in Special Topics in Engineering Science Engineering Science Software Architecture Software Architecture Spring Semester 2004 Spring Semester 2004 Lecture Notes Lecture Notes

Implications of Inheritance (Budd's UOOPJ, Ch. 11 )

Embed Size (px)

DESCRIPTION

Engr 691 Special Topics in Engineering Science Software Architecture Spring Semester 2004 Lecture Notes. Implications of Inheritance (Budd's UOOPJ, Ch. 11 ). This is a set of slides to accompany chapter 11 of Timothy Budd's textbook Understanding Object-Oriented Programming with Java - PowerPoint PPT Presentation

Citation preview

Engr 691Engr 691Special Topics in Engineering ScienceSpecial Topics in Engineering Science

Software ArchitectureSoftware Architecture

Spring Semester 2004Spring Semester 2004

Lecture NotesLecture Notes

Implications of Inheritance Implications of Inheritance (Budd's UOOPJ, Ch. 11(Budd's UOOPJ, Ch. 11))

This is a set of slides to accompany chapter 11 of This is a set of slides to accompany chapter 11 of Timothy Budd's textbook Timothy Budd's textbook

Understanding Object-Oriented Programming with Java Understanding Object-Oriented Programming with Java Updated EditionUpdated Edition

(Addison-Wesley, 2000)(Addison-Wesley, 2000)

Idealization of Idealization of is-ais-a Relationship Relationship

A A TextWindowTextWindow is-ais-a WindowWindow

Because Because TextWindowTextWindow subclasses subclasses WindowWindow, all behavior of , all behavior of WindowWindow present in instances of present in instances of TextWindowTextWindow

Therefore, variable declared as Therefore, variable declared as WindowWindow should be able to should be able to hold value of type hold value of type TextWindowTextWindow

Unfortunately, practical programming language Unfortunately, practical programming language implementation issues complicate this idealized picture.implementation issues complicate this idealized picture.

Impact of Inheritance on Impact of Inheritance on Other Language FeaturesOther Language Features

Support for inheritance and principle of substitutability impacts most Support for inheritance and principle of substitutability impacts most aspects of a programming language:aspects of a programming language:

Polymorphic variables needed Polymorphic variables needed Polymorphic variablePolymorphic variable – variable declared as one type but actually – variable declared as one type but actually

holds value of subtype holds value of subtype Polymorphic variables better if objects allocated on Polymorphic variables better if objects allocated on heapheap rather than rather than stack – storage requirements vary among subtypes stack – storage requirements vary among subtypes Heap allocationHeap allocation– makes makes reference (pointer) semanticsreference (pointer) semantics more natural than copy semantics more natural than copy semantics

for assignment and parameter passing – copy address of object rather for assignment and parameter passing – copy address of object rather than value than value

– makes reference semantics more natural for object identity testing – makes reference semantics more natural for object identity testing – compare addresses – separate operator for object value equalitycompare addresses – separate operator for object value equality

– requires storage management – reference semantics makes manual requires storage management – reference semantics makes manual allocation difficult – allocation difficult – garbage collectiongarbage collection encouraged encouraged

Polymorphic VariablesPolymorphic Variables((class Shapeclass Shape))

class Shape class Shape { { public Shape (int ix, int iy) public Shape (int ix, int iy) { { x = ix; x = ix; y = iy; y = iy; } }

public String describe() public String describe() { { return "unknown shape"; return "unknown shape"; } }

protected int x; protected int x; protected int y; protected int y;

}}

Polymorphic VariablesPolymorphic Variables((class Squareclass Square))

class Square extends Shape class Square extends Shape { { public Square(int ix, int iy, int is) public Square(int ix, int iy, int is) { { super(ix, iy); super(ix, iy); side = is; side = is; } }

public String describe() public String describe() { { return "square with side " + side;return "square with side " + side; } } protected int side; protected int side; }}

Polymorphic VariablesPolymorphic Variables((class Circleclass Circle))

class Circle extends Shape class Circle extends Shape { { public Circle (int ix, int iy, int ir) public Circle (int ix, int iy, int ir) { { super(ix, iy); super(ix, iy); radius = is; radius = is; } } public String describe() public String describe() { { return "circle with radius " + radius;return "circle with radius " + radius; } } protected int radius; protected int radius; }}

Polymorphic VariablesPolymorphic Variables((class ShapeTestclass ShapeTest))

class ShapeTest class ShapeTest { { public static void main(String[] args) public static void main(String[] args) { { Shape form = new Circle(10, 10, 5); Shape form = new Circle(10, 10, 5); System.out.println("form is " System.out.println("form is " + form.describe(); + form.describe(); } } } }

Output of Output of ShapeTestShapeTest: form is circle with radius 5: form is circle with radius 5

Polymorphic Variables Polymorphic Variables (class(class CardPile CardPile from Solitaire)from Solitaire)

public class CardPile { ... } public class CardPile { ... }

class SuitPile extends CardPile { ... } class SuitPile extends CardPile { ... }

class DeckPile extends CardPile { ... } class DeckPile extends CardPile { ... }

class DiscardPile extends CardPile { ... } class DiscardPile extends CardPile { ... }

class TablePile extends CardPile { ...} class TablePile extends CardPile { ...}

Polymorphic VariablesPolymorphic Variables(class(class Solitaire Solitaire from Solitaire Examplefrom Solitaire Example))

public class Solitaire public class Solitaire { ... { ... static public CardPile allPiles [ ]; static public CardPile allPiles [ ]; ... ... public void init () public void init () { // first allocate the arrays { // first allocate the arrays allPiles = new CardPile[13]; allPiles = new CardPile[13]; ... ... allPiles[0] = deckPile = new DeckPile(335, 30); allPiles[0] = deckPile = new DeckPile(335, 30); allPiles[1] = discardPile = new DiscardPile(268, 30); allPiles[1] = discardPile = new DiscardPile(268, 30); for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++) allPiles[2+i] = suitPile[i] allPiles[2+i] = suitPile[i] = new SuitPile(15 + (Card.width+10) * i, 30); = new SuitPile(15 + (Card.width+10) * i, 30); for (int i = 0; i < 7; i++) for (int i = 0; i < 7; i++) allPiles[6+i] = tableau[i] allPiles[6+i] = tableau[i] = new TablePile(15 + (Card.width+5) * i, = new TablePile(15 + (Card.width+5) * i, Card.height + 35, i+1 ); Card.height + 35, i+1 ); } } }}

Polymorphic VariablesPolymorphic Variables(class(class SolitaireFrameSolitaireFrame from Solitairefrom Solitaire))

private class SolitaireFrame extends Frame private class SolitaireFrame extends Frame { ... { ... public void paint(Graphics g) public void paint(Graphics g) { { for (int i = 0; i < 13; i++) for (int i = 0; i < 13; i++) allPiles[i].display(g); allPiles[i].display(g); } } } }

Memory Allocation Memory Allocation in Programming Languagesin Programming Languages

Static allocationStatic allocation

Stack-based allocationStack-based allocation

Heap-based allocationHeap-based allocation

Memory AllocationMemory Allocation Stack-based Allocation Stack-based Allocation

Memory allocated dynamically on runtime stack Memory allocated dynamically on runtime stack Memory allocation/release tied to procedure entry/exit Memory allocation/release tied to procedure entry/exit Space requirement determined at compile time based Space requirement determined at compile time based

on static types on static types Advantage: efficient – all local variables Advantage: efficient – all local variables

allocated/deallocated as a block (activation record) allocated/deallocated as a block (activation record) Disadvantage: polymorphic variable size not known at Disadvantage: polymorphic variable size not known at

compile time – objects stored may vary during compile time – objects stored may vary during execution execution

Memory Allocation Memory Allocation Heap-based AllocationHeap-based Allocation

Memory allocated dynamically from free memory Memory allocated dynamically from free memory area area Memory allocation/release not tied to procedure Memory allocation/release not tied to procedure

entry/exit entry/exit Space requirement determined at run-time based Space requirement determined at run-time based

using dynamic considerations – size known when using dynamic considerations – size known when allocated allocated

Allocated objects accessed by indirection through a Allocated objects accessed by indirection through a pointer (reference in Java) pointer (reference in Java)

Advantage: supports polymorphic variables – values Advantage: supports polymorphic variables – values can be pointers to object on heap can be pointers to object on heap

Disadvantage: considered less efficient than stack-Disadvantage: considered less efficient than stack-based based

Memory Allocation in Java Memory Allocation in Java

All object variables hold pointers to heap-allocated All object variables hold pointers to heap-allocated objects – fixed size on stack, differing sizes on heapobjects – fixed size on stack, differing sizes on heap– variable of type variable of type ShapeShape holds address of object on heap holds address of object on heap

Polymorphic variables thus easy to implementPolymorphic variables thus easy to implement– assignment of assignment of SquareSquare instance to instance to ShapeShape variable means new variable means new

address stored address stored

Primitive type variables hold values, copy on Primitive type variables hold values, copy on assignment, not polymorphic assignment, not polymorphic

Memory Allocation in C++Memory Allocation in C++

Variables stored on stack – enough space allocated to hold instance Variables stored on stack – enough space allocated to hold instance of actual declared type of actual declared type – variable of type variable of type ShapeShape holds actual object holds actual object

"Ordinary" variables are not polymorphic "Ordinary" variables are not polymorphic – assignment of assignment of SquareSquare instance to instance to ShapeShape variable means object copied variable means object copied

with extra field with extra field sliced off sliced off – no– no longer longer CircleCircle

Pointer variables hold addresses of objects – thus support Pointer variables hold addresses of objects – thus support polymorphism polymorphism – assignment of assignment of SquareSquare pointer to pointer to ShapeShape pointer variable means new pointer variable means new

address stored address stored

Objects may be allocated on heap (or on stack or statically) Objects may be allocated on heap (or on stack or statically) – care must be taken with pointers to deallocated objects on stack (or in care must be taken with pointers to deallocated objects on stack (or in

heap memory)heap memory)

Copy versus Reference Copy versus Reference SemanticsSemantics

Copy semantics:Copy semantics: assignment copies entire value of right side to left-side variable assignment copies entire value of right side to left-side variable the two values are independent; changes to one do not affect the two values are independent; changes to one do not affect

other other examples: Java assignments to primitive variables, examples: Java assignments to primitive variables, C++ assignments to non-pointer variables C++ assignments to non-pointer variables

Reference (pointer) semantics:Reference (pointer) semantics: assignment changes left-side variable to refer to right-side valueassignment changes left-side variable to refer to right-side value now two references to same value; if value is changed, it can be now two references to same value; if value is changed, it can be

observed using either reference observed using either reference examples: Java assignments to object variablesexamples: Java assignments to object variables C++ assignments to pointer variables. C++ assignments to pointer variables.

Java Reference Semantics Java Reference Semantics ExampleExample

public class Box public class Box { { public Box() public Box() { value = 0; } { value = 0; } public void setValue(int v) public void setValue(int v) { value = v; } { value = v; }

public int getValue() public int getValue() { return value; } { return value; }

private int value; private int value; }}

Java Reference Semantics Java Reference Semantics Example (continued)Example (continued)

public class BoxTest public class BoxTest { { static public void main(String[] args) static public void main(String[] args) { { Box x = new Box(); Box x = new Box(); x.setValue(7); // sets value of x x.setValue(7); // sets value of x

Box y = x; // assign y the same value as y Box y = x; // assign y the same value as y y.setValue(11); // change value of y y.setValue(11); // change value of y

System.out.println("contents of x " + x.getValue()); System.out.println("contents of x " + x.getValue()); System.out.println("contents of y " + y.getValue()); System.out.println("contents of y " + y.getValue()); } } } }

After After y = xy = x, both , both xx and and yy in in BoxTestBoxTest refer to the same object refer to the same object Call Call y.setValue(11)y.setValue(11) thus changes object referred to by both thus changes object referred to by both xx and and yy Message Message getValue()getValue() thus returns same value (11) for both thus returns same value (11) for both xx and and yy

Creating Copies in JavaCreating Copies in Java

If need copy, explicitly create itIf need copy, explicitly create it

Box y = new Box(x.getValue());Box y = new Box(x.getValue());

If commonly need copy, provide copy-creating methodIf commonly need copy, provide copy-creating method

public class Box public class Box { ... { ... public Box copy() public Box copy() { { Box b = new Box(); Box b = new Box(); b.setValue(getValue()); b.setValue(getValue()); return b; return b; } // return (new Box()).setValue(getValue()) } // return (new Box()).setValue(getValue()) ... ... } }

and use method when needed and use method when needed

Box y = x.copy(); Box y = x.copy();

Creating Copies in JavaCreating Copies in Java

Copy constructorsCopy constructors are sometimes useful are sometimes useful public class Box public class Box

{ ... { ... public Box(Box x) public Box(Box x) { value = x.getValue()); } { value = x.getValue()); } ... ... } }

Base class Base class ObjectObject has protected method has protected method clone()clone() that that creates bitwise copy of receiver creates bitwise copy of receiver

Interface CloneableInterface Cloneable denotes objects that can be denotes objects that can be cloned – no methods in interface, just tagcloned – no methods in interface, just tag– objects needed by some API methods objects needed by some API methods

Example: Java ClonesExample: Java Clones

Make Make BoxBox a a CloneableCloneable object object

Implement interface Implement interface CloneableCloneable

Override method Override method clone()clone() (which returns type (which returns type ObjectObject) )

Make Make clone()clone() public public

Example: Java Clones (cont.)Example: Java Clones (cont.)

public class Box implements Cloneable public class Box implements Cloneable { { public Box() public Box() { value = 0; } { value = 0; } public void setValue(int v) public void setValue(int v) { value = v; } { value = v; }

public int getValue() public int getValue() { return value; } { return value; }

public Object clone() public Object clone() { return (new Box()).setValue(getValue()); } { return (new Box()).setValue(getValue()); }

private int value; private int value; }}

Example: Java Clones (cont.)Example: Java Clones (cont.)

public class BoxTest public class BoxTest { { static public void main(String[] args) static public void main(String[] args) { { Box x = new Box(); Box x = new Box(); x.setValue(7); // sets value of x x.setValue(7); // sets value of x

Box y = (Box) x.clone(); // assign copy of x to y Box y = (Box) x.clone(); // assign copy of x to y y.setValue(11); // change value of y y.setValue(11); // change value of y

System.out.println("contents of x " + x.getValue()); System.out.println("contents of x " + x.getValue()); System.out.println("contents of y " + y.getValue()); System.out.println("contents of y " + y.getValue()); } } } }

Values 7 and 11, respectively, would be printed by Values 7 and 11, respectively, would be printed by BoxTestBoxTest

Shallow versus Deep CopyingShallow versus Deep Copying

Suppose values being held by Suppose values being held by BoxBox objects are objects are themselves objects of type themselves objects of type Shape Shape (instead of (instead of intint) )

BoxBox's 's clone()clone() would would notnot copy copy ShapeShape object object– clones would both refer to same clones would both refer to same ShapeShape object object– clone()clone() creates a creates a shallow copyshallow copy

If internal If internal ShapeShape object also copied, then it is a object also copied, then it is a deep copydeep copy. . – BoxBox's method 's method clone()clone() could call could call ShapeShape's 's clone()clone() operation operation

Decide whether shallow or deep copy is needed for Decide whether shallow or deep copy is needed for application application

Parameter Passing as Parameter Passing as AssignmentAssignment

Parameter-passing is assignment from argument to parameter Parameter-passing is assignment from argument to parameter

Java primitive values are passed by value from argument to Java primitive values are passed by value from argument to parameter – copy semantics parameter – copy semantics – modification of parameter just local, no effect on argument modification of parameter just local, no effect on argument

Java object variables are passed by reference from argument to Java object variables are passed by reference from argument to parameter – reference semantics parameter – reference semantics

Note: Value of reference is copied from argument to parameterNote: Value of reference is copied from argument to parameter Modification of parameter's internal state is change to argument Modification of parameter's internal state is change to argument

Parameter Passing as Parameter Passing as Assignment (continued)Assignment (continued) public class BoxTest public class BoxTest { { static public void main (String[] args) static public void main (String[] args) { { Box x = new Box(); Box x = new Box(); x.setValue(7); // sets value of x x.setValue(7); // sets value of x sneaky(x); sneaky(x); System.out.println("contents of x " System.out.println("contents of x " + x.getValue()); + x.getValue()); } } static void sneaky(Box y) static void sneaky(Box y) { { y.setValue(11); y.setValue(11); } } } }

Value 11 would be printed by Value 11 would be printed by BoxTestBoxTest

Equality Testing Equality Testing Primitive TypesPrimitive Types

How test whether two values of same primitive type are equal? How test whether two values of same primitive type are equal?

Test whether their values are identical – i.e., same bits Test whether their values are identical – i.e., same bits

Java: Java: x == y x == y

What about equality of values of different primitive types? What about equality of values of different primitive types?

In general, will not pass type checker unless well-accepted conversion In general, will not pass type checker unless well-accepted conversion between between

Java: numeric types converted and compared, but otherwise Java: numeric types converted and compared, but otherwise mismatched types means inequality mismatched types means inequality

Equality Testing Equality Testing Object IdentityObject Identity

Some languages will compare the values; others, compare pointers Some languages will compare the values; others, compare pointers (references) (references)

Java uses pointer semantics – i.e., tests object Java uses pointer semantics – i.e., tests object identityidentity

Java Java ==== tests object identity tests object identity Integer x = new Integer(7); Integer x = new Integer(7); Integer y = new Integer(3 + 4); Integer y = new Integer(3 + 4); if (x == y) if (x == y) System.out.println("equivalent") System.out.println("equivalent") else else System.out.println("not equivalentSystem.out.println("not equivalent") ")

Output is "Output is "not equivalentnot equivalent" "

Equality Testing Equality Testing Object Identity (continued)Object Identity (continued)

Objects Objects xx and and yy physically distinct – but same value internally physically distinct – but same value internally

Java type checker disallows comparison of unrelated object types with Java type checker disallows comparison of unrelated object types with ====

But can compare if one an ancestor of other But can compare if one an ancestor of other

Circle x = new Circle(10, 10, 5); Circle x = new Circle(10, 10, 5); Shape y = new Square(10, 10, 5); Shape y = new Square(10, 10, 5); Shape z = new Circle(10, 10,Shape z = new Circle(10, 10, 5); 5);

Above Above x == yx == y and and x == zx == z pass type checking, but neither returns pass type checking, but neither returns truetrue

nullnull is of type is of type ObjectObject; can be compared for equality with any object ; can be compared for equality with any object

Equality Testing Equality Testing Object Value EqualityObject Value Equality

Java Java ObjectObject class has class has equals(Object) meequals(Object) method to do thod to do bitwise comparisons, often redefined bitwise comparisons, often redefined

Continuing the Continuing the Shape/CircleShape/Circle from the previous page from the previous page

if (x.equals(y))if (x.equals(y)) System.out.println("equivalent") System.out.println("equivalent") else else

System.out.println("not equivalent")System.out.println("not equivalent")

Output isOutput is " "equivalentequivalent" "

Equality Testing Equality Testing Object Value Equality (cont.)Object Value Equality (cont.)

Can override Can override equals()equals() to get more appropriate definition to get more appropriate definition

class Circle extends Shape class Circle extends Shape { ... { ... public boolean equals(Object arg) public boolean equals(Object arg) { { return arg instanceof Circle && return arg instanceof Circle &&

radius == ((Circle)arg).radius); radius == ((Circle)arg).radius); } // more compact above than textbook example } // more compact above than textbook example } }

Above Above c.equals(d)c.equals(d) iff iff cc and and dd are both are both CircleCircles with same radius s with same radius regardless of location regardless of location

Should override Should override equals()equals() if object contains other objects if object contains other objects

Equality Testing Equality Testing Object Value Equality (cont.)Object Value Equality (cont.)

But be careful with asymmetric equality comparisonsBut be careful with asymmetric equality comparisons

Suppose override Suppose override equals()equals() in Shape in Shape

class Shape class Shape { ... { ... public boolean equals(Object arg) public boolean equals(Object arg) { { if (arg instanceof Shape) if (arg instanceof Shape) { { Shape s = (Shape)arg; Shape s = (Shape)arg; return x == s.x && y == s.y ; return x == s.x && y == s.y ; } } else else return false; return false; } } } }

But not in subclass But not in subclass SquareSquare

Equality Testing Equality Testing Object Value Equality (cont.)Object Value Equality (cont.)

Now consider Now consider

Square s = new Square(10,10,5); Square s = new Square(10,10,5); Circle c = new Circle(10,10,5); Circle c = new Circle(10,10,5);

if (s.equals(c)) // true, uses Shape method if (s.equals(c)) // true, uses Shape method System.out.println("square equal to circle"); System.out.println("square equal to circle"); if (c.equals(s)) // false, uses Circle method if (c.equals(s)) // false, uses Circle method System.out.println("circle equal to squareSystem.out.println("circle equal to square");");

Changing Method ArgumentsChanging Method Arguments

For equality testing, it might useful to change types of method For equality testing, it might useful to change types of method argumentsarguments

class Shape class Shape { ... { ... public boolean equals (Shape s) public boolean equals (Shape s) { { return false; return false; } } } } class Circle extends Shape class Circle extends Shape { ... { ... public boolean equals (Circle c) { ... } public boolean equals (Circle c) { ... } } }

class Square extends Shape class Square extends Shape { ... { ... public boolean equals (Square sq) { ... } public boolean equals (Square sq) { ... } } }

Covariance and ContravarianceCovariance and Contravariance

An argument or return value made more specialized is An argument or return value made more specialized is covariantcovariant type replaced by descendant of original type type replaced by descendant of original type

An argument made more general is An argument made more general is contravariantcontravariant

Both can destroy Both can destroy is-ais-a relation, have tricky semantics relation, have tricky semantics

Most languages forbid both Most languages forbid both Java and C++ forbid Java and C++ forbid Eiffel supports covariance Eiffel supports covariance

Storage DeallocationStorage Deallocation

Polymorphic variables lead naturally to heap-Polymorphic variables lead naturally to heap-based allocation based allocation

Heap-based allocation requires a storage Heap-based allocation requires a storage deallocation mechanism deallocation mechanism

Two approaches: Two approaches:

Explicit deallocation by programmerExplicit deallocation by programmer

Implicit deallocation by runtime systemImplicit deallocation by runtime system

Storage Deallocation (continued)Storage Deallocation (continued)

Explicit deallocation by programmerExplicit deallocation by programmer

Programmer must return unneeded memory to Programmer must return unneeded memory to system Examples: C++ system Examples: C++ deletedelete, Pascal , Pascal disposedispose

Advantage: efficiency Advantage: efficiency

Disadvantages: Disadvantages: attempted use of memory not yet allocated or already freed attempted use of memory not yet allocated or already freed multiple freeing of memory multiple freeing of memory freeing of memory that is still needed freeing of memory that is still needed memory leak – allocated memory is never releasedmemory leak – allocated memory is never released

Storage Deallocation (continued)Storage Deallocation (continued)

Implicit deallocation by runtime systemImplicit deallocation by runtime system

System detects when data unneeded, automatically System detects when data unneeded, automatically recovers memory recovers memory

Garbage collectionGarbage collection Examples: Java, Smalltalk, Perl Examples: Java, Smalltalk, Perl

Advantage: safety and convenience Advantage: safety and convenience

Disadvantage: relative inefficiency / loss of Disadvantage: relative inefficiency / loss of programmer control programmer control