CS 181 - Object-Oriented Programming

Inheritance

Inheritance = class (subclass) created from existing class (superclass) ... acquiring its data and methods ... and adding new data and methods

subclass could be superclass for some other class

Account -> CheckingAccount -> StudentCheckingAccount

Direct superclass = one level up

Indirect superclass = two or more levels up

Multiple Inheritance = class is subclass of two or more independent superclasses

Student -> StudentEmployee <- Employee

Java does NOT allow Multiple Inheritance

Java does allow Interfaces, which have advantages of multiple inheritance without associated problems

Subclass more specific than superclass, represents smaller group of objects

Each object of subclass is also an object of superclass

public class Subclass extends Superclass {...}

Subclass can (and often does) have its own method with same signature (same number and type of parameters, same return type) as Superclass method

CheckingAccount monthlyFee StudentCheckingAccount monthlyFee public float monthlyFee() { fee = super.monthlyFee() + .....; }

use "super" to refer to superclass method

super(...) refers to superclass constructor

object of subclass can be treated as object of superclass

CheckingAccount check = new CheckingAccount (...); StudentCheckingAccount stucheck = new StudentCheckingAccount(...); check = stucheck;

Any method for CheckingAccount or StudentCheckingAccount works. Java knows that check is really a StudentCheckingAccount and will use those methods if available. If not, it will use CheckingAccount methods.

stucheck = (StudentCheckingAccount) check;

Explicit cast required and this only works if check really is a stucheck

Access Modifier protected

Any methods can access public members of superclass

Subclass methods CANNOT access private members of superclass

Subclass methods CAN access protected members of superclass

"Protected" means private to this class and any subclasses

Good idea to use "protected" instead of "private" in classes that might be used as superclasses

Inheritance example

// Fig. 7.4: Point.java public class Point { // coordinates of the Point protected int x, y; // Constructors public Point() {setPoint( 0, 0 );} public Point( int a, int b ) { setPoint( a, b ); } // Set x and y coordinates of Point public void setPoint(int a, int b) { x = a; y = b; } // get x coordinate public int getX() { return x; } // get y coordinate public int getY() { return y; } // convert the point into a String public String toString() {return "[" + x + ", " + y + "]";} } // Fig. 7.4: Circle.java public class Circle extends Point { // inherits from Point protected double radius; // No-argument constructor public Circle() { // implicit call to // to superclass constructor setRadius( 0 ); } // Constructor public Circle (double r, int a, int b) { super( a, b ); // call to superclass constructor setRadius( r ); } // Set radius of Circle public void setRadius( double r ) {radius = ( r >= 0.0 ? r : 0.0 ); } // Get radius of Circle public double getRadius() { return radius; } // Calculate area of Circle public double area() {return Math.PI * radius * radius;} // convert the Circle to a String public String toString() { return "Center = " + "[" + x + ", " + y + "]" + "; Radius = " + radius; } }

In Java EVERY class extends another class

public class MyTime [extends Object]

Object is in java.lang and provides a set of methods for any class

Circle objects can use both Circle constructors, setRadius, getRadius, area, toString as well as Point's setPoint, getX, getY and instance variables x and y

Subclass constructors and finalizers

// Fig. 7.5: Circle.java public class Circle extends Point { // inherits from Point protected double radius; // no-argument constructor public Circle() { // implicit call to // to superclass constructor setRadius( 0 ); } // Constructor public Circle (double r, int a, int b) { super( a, b ); setRadius( r ); } // finalizer protected void finalize() throws Throwable { super.finalize(); // call superclass finalize method } ... // convert the Circle to a String public String toString() { return "Center = " + super.toString() + "; Radius = " + radius; } } // Fig. 7.5: Test.java import java.awt.Graphics; import java.applet.Applet; public class Test extends Applet { private Circle circle1, circle2; public void init() { circle1 = new Circle( 4.5, 72, 29 ); circle2 = new Circle( 10, 5, 5 ); } public void start() { circle2 = null; circle1 = null; // Circles can be garbage collected System.gc(); // call the garbage collector } }

Call to superclass constructor (if present) must be first line in subclass constructor

Constructor invocation order: superclass constructor, then subclass constructor

finalize() should always be protected to give subclasses access to it

"throws Throwable" is part of exception handling

Java does not guarantee order in which garbage will be collected or finalizers run

Three level example

// Fig. 7.6: Point.java public class Point { protected int x, y; public Point() {setPoint( 0, 0 );} public Point( int a, int b ) { setPoint( a, b ); } public void setPoint(int a, int b) { x = a; y = b; } public int getX() { return x; } public int getY() { return y; } public String toString() {return "[" + x + ", " + y + "]";} } // Fig. 7.7: Circle.java public class Circle extends Point { // inherits from Point protected double radius; public Circle() { // implicit call to constructor setRadius( 0 ); } public Circle ( double r, int a, int b ) { super( a, b ); setRadius( r ); } public void setRadius( double r ) {radius = ( r >= 0.0 ? r : 0.0 );} public double getRadius() { return radius; } public double area() {return Math.PI * radius * radius;} public String toString() { return "Center = " + super.toString() + "; Radius = " + radius; } } // Fig. 7.8: Cylinder.java public class Cylinder extends Circle { protected double height; // height of Cylinder // No-argument constructor public Cylinder() { // implicit call to superclass // constructor here setHeight( 0 ); } // constructor public Cylinder (double h, double r, int a, int b) { super( r, a, b ); setHeight( h ); } // Set height of Cylinder public void setHeight( double h ) { height = ( h >= 0 ? h : 0 ); } // Get height of Cylinder public double getHeight() { return height; } // Calculate area of Cylinder public double area() { return 2 * super.area() + 2 * Math.PI * radius * height; } // Calculate volume of Cylinder public double volume() { return super.area() * height; } // Convert the Cylinder to a String public String toString() { return super.toString() + "; Height = " + height; } }

Polymorphism

Treat subclass object as a superclass object

Dynamic Method Binding = All subclasses of a superclass can have their own methods (like monthlyFee). All can be very different. Superclass reference to subclass object will choose correct method dynamically.

Nice to call anyAccount.monthlyFee() and let runtime system determine which subclass monthlyFee() to use. The type of an object need not be known at compile time!

To do this, declare monthlyFee() in Account and override it in each subclass

Same message sent to various objects (anyAccount.monthlyFee()) takes on "many forms" ("poly-morphism")

New subclasses can be added without need to change superclass

Add new subclass of Account (DebitAccount), define monthlyFee() for DebitAccount and everything works with no modification

Abstract Classes

Abstract Class = class which will never be used to instantiate any objects

Purpose of abstract class is to provide superclass from which other classes may inherit

Use keyword "abstract"

Classes for which objects may be instantiated are "concrete classes"

Some class hierarchies have one or two class levels at top that are abstract classes

Any new class that inherits from abstract class must implement all abstract methods

Example of Abstract Classes and Polymorphism

// Fig. 7.9: Employee.java public abstract class Employee { private String firstName; private String lastName; // Constructor public Employee ( String first, String last ) { firstName = first; lastName = last; } // Return the first name public String getFirstName() { return firstName; } // Return the last name public String getLastName() { return lastName; } public String toString() { return firstName + ' ' + lastName; } // Abstract method that must be // implemented for each derived // class of Employee from which // objects are instantiated. public abstract double earnings(); } // Fig. 7.9: CommissionWorker.java public final class CommissionWorker extends Employee { private double salary; private double commission; private int quantity; // Constructor for class public CommissionWorker (String first, String last, double s, double c, int q) { super( first, last ); setSalary( s ); setCommission( c ); setQuantity( q ); } public void setSalary( double s ) { salary = ( s > 0 ? s : 0 ); } public void setCommission(double c) {commission = ( c > 0 ? c : 0 );} public void setQuantity( int q ) { quantity = ( q > 0 ? q : 0 ); } public double earnings() { return salary + commission * quantity; } public String toString() { return "Commission worker: " + super.toString(); } } // Fig. 7.9: HourlyWorker.java public final class HourlyWorker extends Employee { private double wage; private double hours; public HourlyWorker (String first, String last, double w, double h) { super( first, last ); setWage( w ); setHours( h ); } public void setWage( double w ) { wage = ( w > 0 ? w : 0 ); } public void setHours( double h ) { hours = ( h >= 0 && h < 168 ? h : 0 ); } public double earnings() { return wage * hours; } public String toString() { return "Hourly worker: " + super.toString(); } } // Fig. 7.9: Test.java import java.awt.Graphics; import java.applet.Applet; import java.text.DecimalFormat; public class Test extends Applet { private Employee ref; // superclass reference private CommissionWorker c; private HourlyWorker h; public void init() { c = new CommissionWorker ( "Sue", "Jones", 400.0, 3.0, 150); h = new HourlyWorker ( "Karen", "Price", 13.75, 40 ); } public void paint( Graphics g ) { DecimalFormat precision2 = new DecimalFormat( "#.00" ); ref = c; g.drawString (ref.toString() + " earned $" + precision2.format(ref.earnings()), 25, 55 ); ref = h; (ref.toString() + " earned $" + precision2.format(ref.earnings()), 25, 115 ); } }

Another Example of Abstract Classes and Polymorphism

// Fig. 7.10: Shape.java public abstract class Shape { public double area() { return 0.0; } public double volume() { return 0.0; } public abstract String getName(); } // Fig. 7.10: Point.java public class Point extends Shape { protected int x, y; public Point() {setPoint( 0, 0 );} public Point( int a, int b ) { setPoint( a, b ); } public void setPoint(int a, int b) { x = a; y = b; } public int getX() { return x; } public int getY() { return y; } public String toString() { return "[" + x + ", " + y + "]"; } public String getName() { return "Point"; } } // Fig. 7.10: Circle.java public class Circle extends Point { // inherits from Point protected double radius; public Circle() { setRadius( 0 ); } public Circle ( double r, int a, int b ) { super( a, b ); setRadius( r ); } public void setRadius( double r ) { radius = ( r >= 0 ? r : 0 ); } public double getRadius() { return radius; } public double area() { return Math.PI * radius * radius; } public String toString() { return "Center = " + super.toString() + "; Radius = " + radius; } public String getName() { return "Circle"; } } // Fig. 7.10: Cylinder.java public class Cylinder extends Circle { protected double height; public Cylinder() { setHeight( 0 ); } public Cylinder (double h, double r, int a, int b) { super( r, a, b ); setHeight( h ); } public void setHeight( double h ) { height = ( h >= 0 ? h : 0 ); } public double getHeight() { return height; } public double area() { return 2 * super.area() + 2 * Math.PI * radius * height; } public double volume() { return super.area() * height; } public String toString() { return super.toString() + "; Height = " + height; } public String getName() { return "Cylinder"; } } // Fig. 7.10: Test.java import java.awt.Graphics; import java.applet.Applet; import java.text.DecimalFormat; public class Test extends Applet { private Point point; private Circle circle; private Cylinder cylinder; private Shape arrayOfShapes[]; public void init() { point = new Point( 7, 11 ); circle = new Circle( 3.5, 22, 8 ); cylinder = new Cylinder( 10, 3.3, 10, 10 ); arrayOfShapes = new Shape[ 3 ]; arrayOfShapes[ 0 ] = point; arrayOfShapes[ 1 ] = circle; arrayOfShapes[ 2 ] = cylinder; } public void paint( Graphics g ) { // Loop through arrayOfShapes for ( int i = 0; i < arrayOfShapes.length; i++ ) { g.drawString (arrayOfShapes[i].getName() + ": " + arrayOfShapes[i].toString(), 25, yPos ); yPos += 15; g.drawString ("Area = " + precision2.format( arrayOfShapes[i].area() ), 25, yPos ); yPos += 15; g.drawString ("Volume = " + precision2.format( arrayOfShapes[i].volume() ), 25, yPos ); yPos += 30; } } }

Interfaces

Interface contains group of public abstract methods

Class must specify that it implements the interface and must define every method in the interface

Interface typically used instead of abstract class when there is no default implementation

// Fig. 7.11: Shape.java interface Shape { double area(); double volume(); String getName(); } // Fig. 7.11: Point.java public class Point implements Shape { protected int x, y; public Point() {setPoint( 0, 0 );} public Point( int a, int b ) { setPoint( a, b ); } public void setPoint( int a, int b ) { x = a; y = b; } public int getX() { return x; } public int getY() { return y; } public String toString() {return "[" + x + ", " + y + "]";} public double area() {return 0.0;} public double volume() { return 0.0; } public String getName() { return "Point"; } }

Benefit of using interfaces = class can implement as many interfaces as needed in addition to extending a class

class CheckingAccount extends Account implements CheckingInstrument, BankVehicle {...}