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 {...}