Chap. 2. Object-Oriented Design. Inheritance Building ApartmentHouse Commercial Building Low-rise...

Preview:

Citation preview

Chap. 2. Object-Oriented Design

Inheritance

Building

Apartment HouseCommercial

Building

Low-riseApartment

High-riseApartment

Two-storyHouse

Ranch Skyscraper

An example of an “is a” hierarchy involving architectural buildings

class: S fields: x

methods: a() b() c()

class: T fields: y

methods: d() e()

extends

Polymorphism

• Polymorphism refers to the ability of an object variable to take different forms.

• If both S and T define an a() method, when o refers to an object from class T, it uses T’s a() when o.a() is called; when o refers to an object from class S, then it uses S’s a() when o.a() is called.

• Thus, the object o is polymorphic.

Overloading

• Overloading is a useful technique related to polymorphism.

• Overloading occurs when a single class T has multiple methods with the same name, but different signature.

• The signature of a method is a combination of its name and the type and number of arguments that are passed to it.

• For example, suppose a class T, which defines a method a(), extends a class U, which defines a method a(x,y).

• If an object o from class T receives the message “o.a(x,y)”, then U’s version of method a is invoked.

• Inheritance, polymorphism, and method overloading support the development of reusable software.

• In Java, each class can extend exactly one other class.

• Java uses two kinds of method overriding, refinement and replacement.

• In the replacement type of overriding, a method completely replaces the method of the superclass that it is overriding.

• In the refinement type of overriding, a method does not replace the method of its superclass, but instead adds additional code to that of its superclass.

• In Java, constructors use the refinement type of method overriding whereas regular methods use replacement.

The Keyword this

this is used as reference to the current instance of a class. It is useful, for example, when we want to pass the current object as a parameter to some method.

public class ThisTester {// instance variable public int dog = 2; // constructor ThisTester( ) { // null constructor } public void clobber( ) { double dog = 5.0; this.dog = (int) dog; // two different dogs! }

public static void main(String args[]) { ThisTester t = new ThisTester(); System.out.println(“The dog field = “+ t.dog); t.clobber(); System.out.println(“After clobbering, dog = “ + t.dog); }}Output: The dog field = 2 After clobbering, dog = 5

An example to pass arguments to methods

class Car { String licensePlate = ""; // e.g. "New York 543 A23" double speed = 0.0; // in kilometers per hour double maxSpeed = 120.0; // in kilometers per hour

// accelerate to maximum speed // put the pedal to the metal void floorIt() { this.speed = this.maxSpeed; } void accelerate(double deltaV) {

this.speed = this.speed + deltaV; if (this.speed > this.maxSpeed) { this.speed = this.maxSpeed; } if (this.speed < 0.0) { this.speed = 0.0; }

} }

class: Progression

fields: long first long cur

methods: Progression( ) long firstValue() long nextValue()void printProgession(int)

class: ArithProgression

fields: long inc

methods: ArithProgression( ) ArithProgression(long) long nextValue()

class: GeomProgression

methods: GeomProgression( ) GeomProgression(long) long nextValue()

class: FibonacciProgression

fields: long prev

methods: FibonacciProgression( )FibonacciProgression(long, long) long nextValue( )

fields:

extends extends extends

Inheritance Example A generic class for numeric progressions

public class Progression {// First value of the progression. protected long first;// Current value of the progression. protected long cur; // Default constructor Progression() { cur = first = 0; }

// Resets the progression to the first valueprotected long firstValue( ) { cur = first; return cur;}

// Advances the progression to the next value.protected long nextValue( ) { return ++cur; // default next value}

// Prints the first n values of the progressionpublic void printProgression(int n) { System.out.print(firstValue( )); for (int i=2; i<= n; i++) System.out.print(“ “+nextValue()); System.out.println( ); // ends the line }}

Inheritance Example An Arithmetic Progression class

class ArithProgression extends Progression { // Increment protected long inc;

// Inherits variables first and cur // Default constructor setting a unit increment ArithProgression( ) { this(1); }

// Parametric constructor providing the increment ArithProgression(long increment) { inc = increment;}

// Advances the progression by adding the increment to the current value protected long nextValue( ) { cur += inc; return cur; } // Inherits methods firstValue( ) and printProgression(int)}

Inheritance Example A Geometric Progression class

class GeomProgression extends Progression {// Inherits variables first and cur// Default constructor setting base 2 GeomProgression( ) { this(2); }

// Parametric constructor providing the base GeomProgression(long base) { first = base; cur = first;}

// advances the progression by multiplying the base with the current valueprotected long nextValue( ) { cur *= first; return cur; }

// Inherits methods firstValue( ) and printProgression(int)}

Inheritance Example A Fibonacci Progression class

class FibonacciProgression extends Progression {// Previous value long prev; // Inherits variables first and cur FibonacciProgression( ) { this(0,1); } // Parametric constructor providing the first and the second values FibonacciProgression(long value1, long value2) { first = value1; prev = value2 – value1; // fictitious value preceding the first}// Advances the progression by adding the previous value to the current value protected long nextValue( ) { long temp = prev; prev = cur; cur += temp; return cur; }// Inherits methods firstValue( ) and printProgression(int)}

// Test program for the progression classesclass Tester { public static void main (String[ ] args) { Progression prog; // test ArithProgression System.out.println(“Arithmetic progression with default increment:”); prog = new ArithProgression( ); prog.printProgression(10); System.out.println(“Arithmetic progression with increment 5:”); prog = new ArithProgression(5); prog.printProgression(10);// test GeomProgression System.out.println(“Geometric progression with default base:”); prog = new GeomProgression( ); prog.printProgression(10); System.out.println(“Geometric progression with base 3:”); prog = new GeomProgression(3); prog.printProgression(10); // test FibonacciProgression System.out.println(“Fibonacci progression with default start values:”); prog = new FibonacciProgression( ); prog.printProgression(10); System.out.println(“Fibonacci progression with start values 4 and 6:”); prog = new FibonacciProgression(4,6); prog.printProgression(10); } }

Exceptions

• In Java, exceptions are objects that are “thrown” by code that encounters some sort of unexpected condition.

• They can also be thrown by the Java run-time environment should it encounter an unexpected condition, like running out of object memory.

A throw statement is typically written as:throw new <exception_constructor>([<param>,<param>,…]);

e.g.:if (insertIndex > size( )) { throw new BoundaryViolationException(“No element at index “ + insertIndex);

e.g.: // can specify all the exceptions that might be thrown by a methodpublic void goShopping( ) throws ShoppingListTooSmallException,

OutOfMoneyException { // method body …}

Catching Exceptions

The general syntax for a try-catch block in Java is as follows:

try <block_of_statements_1>catch (<exception_type> <identifier>) <block_of_statements_2>[catch (<exception_type> <identifier>) <block_of_statements_3>]…[finally <block_of_statements_n>]

E.g.:

int index = Integer.MAX_VALUE; //2.14 Billion

try // This code might have a problem …{ String toBuy = shoppingList[index];}catch (ArrayIndexOutOfBoundsException aioobx){ System.out.println(“The index “+index+” is outside the array.”);}

E.g.:

catch (ArrayIndexOutOfBoundsException aioobx) { throw new ShoppingListTooSmallException( “Product index is not in the shopping list”);}

Interface

• An interface is a collection of method declarations with no data and no bodies.

• When a class implements an interface, it must implement all of the methods declared in the interface.

• The compiler or run-time system requires that the types of parameters that are actually passed to methods rigidly conform with the type specified in the interface. This requirement is known as strong typing.

Example

// Interface for objects that can be soldpublic interface Sellable {// description of the object public String description(); // list price in cents public int listPrice(); // lowest price in cents we will accept public int lowestPrice();}

// class for photographs that can be soldpublic class Photograph implements Sellable { private String descript; // description of this photo private int price; // the price we are setting private boolean color; // true if photo is in color public Photograph(String desc, int p, boolean c) { // constructor descript = desc; price = p; color = c;} public String description() { return descript; } public int listPrice() { return price; } public int lowestPrice() { return price/2; } public boolean isColor() { return color; }}

// Interface for objects that can be transported

public interface Transportable {

// weight in grams

public int weight();

// whether the object is hazardous

public boolean isHazardous();

}

// Class for objects that can be sold, packed, and shippedpublic class BoxedItem implements Sellable, Transportable { private String descript; // description of this item private int price; // list price in cents private int weight; // weight in grams private boolean haz; // true if object is hazardous private int height=0; // box height in centimeters private int width=0; // box width in centimeters private int depth=0; // box depth in centimeters// constructorspublic BoxedItem (String desc, int p, int w, boolean h) { descript = desc; price = p; weight = w; haz = h;} public String description() { return descript; } public int listPrice() { return price; } public int lowestPrice() {return price/2;} public int weight() { return weight; } public boolean isHazardous() {return haz;} public int insuredValue() {return price*2;} public void setBox(int h, int w, int d) { height = h; width = w; depth = d; }}

Multiple Inheritance in Interfaces

In Java, multiple inheritance is allowed for interfaces but not for classes.

e.g.:

public interface InsurableItem extends Transportable, Sellable { public int insuredValue(); // return insured Value in cents}

public class BoxedItem implements InsurableItem {// … rest of code exactly as before}

Abstract Classes

• An abstract class is a class that contains empty method declarations (that is, declarations of methods without bodies) as well as concrete definitions of methods and/or instance variables.

• An abstract class lies between an interface and a complete concrete class.

E.g.:• A concrete number class, such as java.lang.Integer and

java.lang.Double, extends the java.lang.Number class and fills in the details for the abstract methods of the superclass.

Casting in an Inheritance Hierarchy

Number n;

Integer i;

n = new Integer(3);

i = (Integer)n; // This is legal

n = new Double(3.1415);

i = (Integer) n; // This is illegal

Number n;

Integer i;

n = new Integer(3);

if (n istanceof Integer)

i = (Integer) n; // This is legal

n = new Double(3.1415);

if ( n instanceof Integer)

i = (Integer) n; // This will not be attempted

Casting with Interface

public interface Person {

public boolean equalTo (Person other); // is this the same person

public String getName( ); // get this person’s name

public int getAge( ); // get this person’s age

}

public class Student implements Person { String id; String name; int age;

public Student (String i, String n, int a) {// simple constructor id = i; name = n; age = a; }

protected int studyHours( ) { return age/2;} // just a guess public String getID( ) { return id; } // ID of the student public String getName( ) { return name;} // from Person interface public int getAge( ) { return age; }// from Person interface public boolean equalTo(Person other) { // from Person interface Student otherStudent = (Student) other; // cast Person to Student return (id.equals(otherStudent.getID( ))); // compare IDs }}

public class PersonPairDirectory {// … instance variables would go here … public PersonPairDirectory() {//default constructor goes here} public void insert (Person person, Person other) { // insert code goes

here } public Person findOther (Person person) { return null; } // stub for find public void remove (Person person, Person other) { // remove code goes

here }}

Student cute_one = myDirectory.findOther(smart_one); // wrong!

Student cute_one = (Student) (myDirectory.findOther(smart_one));

Recursion

Factorial(n)=

1 if n=0

n*factorial(n-1) if n>=1.

public static int recursiveFactorial(int n) { // recursive factorial function

if (n==0) return 1; // base case

else return n*recursiveFactorial(n-1); // recursive case

}

The Adapter Pattern

• The adapter pattern applies to any context where we want to modify an existing class so that its methods match those of a related, but different, class or interface.

• One general way for applying the adapter pattern is to define the new class in such a way that it contains an instance of the old class as a hidden field, and implement each method of the new class using methods of this hidden instance variable.

class StudentPairDirectory adapting class PersonPairDirectory

// Class for a directory storing pairs of Student objectspublic class StudentPairDirectory { protected PersonPairDirectory directory; public StudentPairDirectory() { directory=new PersonPairDirectory();} public void insert(Student s, Student t) {directory.insert(s,t);} public Student findOther(Student s) { return (Student) directory.findOther(s); } public void remove(Student s, Student t) { directory.remove(s,t); }}

Recommended