Lecture 2, 1/30: Abstract Methods and Interfaces

Abstract Methods

Not covered in DJW.

An abstract method is a method with no code.

An abstract class A is a class with at least one abstract method M

The abstract class can contain a concrete method G that calls M.

You cannot construct an object of type A. What you can do is define a concrete subclass S of A that overrides A's definition of M with a concrete method.

Then construct an object O of class S and call O.G(...). When G needs to call M, it will find the M that belongs to Q (dynamic dispatching!), which is the M defined for S.

Figures.java.

Abstract class: Figure.
Data field: boundingBox
Abstract methods: area, inside .

Concrete class Rect extends Figure .
Inherits field boundingBox.
Provides instantiation for area, inside.

Concrete class Circle extend Figure
Inherits field boundingBox.
Provides instantiation for area, inside.

Question. Suppose that we define Figure as a concrete class, and define area and inside in some arbitrary way as concrete methods
(e.g. area always returns 1.0 and inside always returns true.)
How would that affect what this code does?

What is the point of having abstract methods?

Calling a function with various subfunctions

Sometimes you want to need to do some particular operation with a variety of different functions. E.g. and so on.

The obvious thing would be to write functions of the form ApplyToArray(A,B,F) or Trapezoid(F,A,B,N), which take F as a parameter. There are programming languages that allow this, with lesser and greater degrees of generality. However, Java is not one of them.

If all the functions you are considering have the same type signature, then Java provides two techniques for doing this: abstract methods and interfaces. If you consider functions that take and return different possible types, then you have to add on generics.

Trapezoid Rule

ApplierAbs.java.

Abstract class: ArrayApplier
Abstract method: f
Concrete method: of ApplyToArray is ApplyToArray(A,B)
Concrete class applyIncr extends ArrayApplier, and overrides f with an increment function.
Concrete class applyDouble extends ArrayApplier, and overrides f with a doubling function.

The main method creates an object Incr of class applyIncr and calls Incr.ApplyToArray(A,B).
When this calls f it calls Incr's version of f which is the one defined in applyIncr.

Note that these classes have no data fields, only methods. So you never need more than one object of these classes, which makes them a little strange.

TrapezoidAbs.java.

The trapezoid rule gives an approximation of the definite integral.

Abstract class: Trapezoid
Abstract method: f, the function to be integrated.
Concrete method: ComputeTrapezoid, which implements the general trapezoid algorithm, calling f
Concrete class: TrapezoidSquare extends Trapezoid, overriding f as f(x) = x^2.
Concrete class: TrapezoidW extends Trapezoid, overriding f as f(x) = 1/(1+x^2).

Interfaces

DJW section 2.1.

An interface I is a collection of abstract methods e.g. f

Class C implements I, instantiates f as a concrete method.

Method M has a formal parameter Xof type I..
Some function calls M(Y) where Y is of type C.
When M calls X.f(), this uses the definition of Q in C

A class can implement many different interfaces.

ApplierInt.java.

Interface: IntFun with abstract method f.
Incr implements IntFun and instantiatesf with the increment function.
Doub implements IntFun and instantiatesf with the doubling function.
ApplyToArray takes an argument Q of type IntFun.
main creates object Inc of type Incr. main calls ApplyToArray(Inc,A,B).
When ApplyToArray calls Q.f(A[i]), since Q is bound to Inc, the version of f defined in Incr is used.
Same thing for Dub

TrapezoidInt.java.

Interface: Integrand with abstract method f.
XSquared implements IntFun and instantiatesf with the function f(x)=x^2.
WW implements Integrand and instantiatesf with the function f(x)=1/(1+x^2).
ComputeTrapezoid takes an argument Q of type Integrand.
main creates object XS of type XSquared. main calls ComputeTrapezoid(XS,A,B).
When ComputeTrapezoid calls Q.f(...), since Q is bound to XS, the version of f defined in XSquared is used.
Same thing for WW.