Abstract Classes and Interfaces in Java: CS61B Lecture #9, Slides of Data Structures and Algorithms

Lecture notes from cs61b lecture #9 at uc berkeley, covering abstract methods and classes, concrete subclasses, interfaces, and a puzzle related to method inheritance in java. It also includes examples of maps and histograms in java.

Typology: Slides

2012/2013

Uploaded on 04/27/2013

netii
netii šŸ‡®šŸ‡³

4.4

(7)

91 documents

1 / 24

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CS61B Lecture #9: Abstract Classes and All That
Public Service Announcement:
•Upsilon Pi Epsilon (UPE), the CS honor society, holds tutoring and
advising services for students. Friendly, courteous students who
understand what you’re going through can help. For further infor-
mation, go to http://upe.cs.berkeley.edu/services/tutoring
Last modified: Wed Feb 8 16:11:43 2006 CS61B: Lecture #9 1
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18

Partial preview of the text

Download Abstract Classes and Interfaces in Java: CS61B Lecture #9 and more Slides Data Structures and Algorithms in PDF only on Docsity!

CS61B Lecture #9: Abstract Classes and All That

Public Service Announcement:

• Upsilon Pi Epsilon (UPE), the CS honor society, holds tutoring and

advising services for students. Friendly, courteous students who

understand what you’re going through can help. For further infor-

mation, go to http://upe.cs.berkeley.edu/services/tutoring

Abstract Methods and Classes

• Instance method can be abstract: No body given; must be supplied

in subtypes.

• One good use is in specifying a pure interface to a family of types:

/** A drawable object. / public abstract class Drawable { // "abstract" = "can’t say new Drawable" /* Expand THIS by a factor of SIZE / public abstract void scale (double size); /* Draw THIS on the standard output. */ public abstract void draw (); }

Now a Drawable is something that has at least the operations scale

and draw on it. Can’t create a Drawable because it’s abstract—in

particular, it has two methods without any implementation.

• BUT, we can write methods that operate on Drawables:

void drawAll (Drawable[] thingsToDraw) { for (int i = 0; i < thingsToDraw.length; i += 1) thingsToDraw[i].draw (); }

• But draw has no implementation! How can this work?

Interfaces

• In generic use, an interface is a ā€œpoint where interaction occurs

between two systems, processes, subjects, etc.ā€ ( Concise Oxford

Dictionary).

• In programming, often use the term to mean a description of this

generic interaction, specifically, a description of the functions or

variables by which two things interact.

• Java uses the term to refer to a slight variant of an abstract class

that contains only abstract methods (and static constants).

• Idea is to treat Java interfaces as the public specifications of data

types, and classes as their implementations:

public interface Drawable { void scale (double size); // Automatically public abstract. void draw (); }

public class Rectangle implements Drawable { ... }

• Interfaces are automatically abstract: can’t say new Drawable();

can say new Rectangle(...).

Multiple Inheritance

• Can extend one class, but implement any number of interfaces.

• Contrived Example:

interface Readable { | void copy (Readable r, Object get (); | Writable w) } | { | w.put (r.get ()); interface Writable { | } void put (Object x); | } | | class Source implements Readable { | class Sink implements Writable { public Object get () { ... } | public void put (Object x) { ... } } | }

class Variable implements Readable, Writable { public Object get () { ... } public void put (Object x) { ... } }

• The first argument of copy can be a Source or a Variable. The

second can be a Sink or a Variable.

Map in Java

/** Function with one integer argument */ | IntList map (IntUnaryFunction proc, | IntList items) { public interface IntUnaryFunction { | if (items == null) int apply (int x); | return null; } | else return new IntList ( | proc.apply (items.head), | map (proc, items.tail) | ); | }

• It’s the use of this function that’s clumsy. First, define class for

absolute value function; then create an instance:

class Abs implements IntUnaryFunction { public int apply (int x) { return Math.abs (x); } }


map (new Abs (), some list);

• Or, we can write a lambda expression (sort of):

map (new IntUnaryFunction () { public int apply (int x) { return x*x; } }, some list);

A Puzzle

class A { void f () { System.out.println ("A.f"); } void g () { f (); /* or this.f() */ } //static void g (A y) { y.f(); } }

| class B extends A { | void f () { | System.out.println ("B.f"); | } | } class C { static void main (String[] args) { B aB = new B (); h (aB); }

static void h (A x) { x.g() } //static void h (A x) { A.g(x); } x.g(x) also legal here }

1. What is printed?

2. What if we made g static?

3. What if we made f static?

4. What if f were not defined in A?

Choices:

a. A.f

b. B.f

c. Some kind of error

A Puzzle

class A { void f () { System.out.println ("A.f"); } //void g () { f (); /* or this.f() */ } static void g (A y) { y.f(); } }

| class B extends A { | void f () { | System.out.println ("B.f"); | } | } class C { static void main (String[] args) { B aB = new B (); h (aB); }

//static void h (A x) { x.g() } static void h (A x) { A.g(x); } x.g(x) also legal here }

1. What is printed?

2. What if we made g static?

3. What if we made f static?

4. What if f were not defined in A?

Choices:

a. A.f

b. B.f

c. Some kind of error

A Puzzle

class A { void f () { System.out.println ("A.f"); } //void g () { f (); /* or this.f() */ } static void g (A y) { y.f(); } }

| class B extends A { | void f () { | System.out.println ("B.f"); | } | } class C { static void main (String[] args) { B aB = new B (); h (aB); }

//static void h (A x) { x.g() } static void h (A x) { A.g(x); } x.g(x) also legal here }

1. What is printed?

2. What if we made g static?

3. What if we made f static?

4. What if f were not defined in A?

Choices:

a. A.f

b. B.f

c. Some kind of error

A Puzzle

class A { static void f () { System.out.println ("A.f"); } void g () { f (); /* or this.f() */ } //static void g (A y) { y.f(); } }

| class B extends A { | static void f () { | System.out.println ("B.f"); | } | } class C { static void main (String[] args) { B aB = new B (); h (aB); }

static void h (A x) { x.g() } //static void h (A x) { A.g(x); } x.g(x) also legal here }

1. What is printed?

2. What if we made g static?

3. What if we made f static?

4. What if f were not defined in A?

Choices:

a. A.f

b. B.f

c. Some kind of error

A Puzzle

class A {

void g () { f (); /* or this.f() */ } //static void g (A y) { y.f(); } }

| class B extends A { | void f () { | System.out.println ("B.f"); | } | } class C { static void main (String[] args) { B aB = new B (); h (aB); }

static void h (A x) { x.g() } //static void h (A x) { A.g(x); } x.g(x) also legal here }

1. What is printed?

2. What if we made g static?

3. What if we made f static?

4. What if f were not defined in A?

Choices:

a. A.f

b. B.f

c. Some kind of error

Answer to Puzzle

1. Executing java C prints , because

1. C.main calls h and passes it aB, whose dynamic type is B.

2. h calls x.g(). Since g is inherited by B, we execute the code for

g in class A.

3. g calls this.f (). Now this contains the value of h’s argument,

whose dynamic type is B. Therefore, we execute the definition of

f that is in B.

4. In calls to f, in other words, static type is ignored in figuring out

what method to call.

2. If g were static, we see ; selection of f still depends on dynamic

type of this.

3. If f were static, would print because then selection of f would

depend on static type of this, which is A.

4. If f were not defined in A, we’d get.

Answer to Puzzle

1. Executing java C prints B.f, because

1. C.main calls h and passes it aB, whose dynamic type is B.

2. h calls x.g(). Since g is inherited by B, we execute the code for

g in class A.

3. g calls this.f (). Now this contains the value of h’s argument,

whose dynamic type is B. Therefore, we execute the definition of

f that is in B.

4. In calls to f, in other words, static type is ignored in figuring out

what method to call.

2. If g were static, we see B.f; selection of f still depends on dynamic

type of this.

3. If f were static, would print A.f because then selection of f would

depend on static type of this, which is A.

4. If f were not defined in A, we’d get a compile-time error.

Specification Seen by Clients

• The clients of a module (class, program, etc.) are the programs or

methods that use that module’s exported definitions.

• In Java, intention is that exported definitions are designated public.

• Clients are intended to rely on specifications, not code.

• Syntactic specification: method and constructor headers—syntax

needed to use.

• Semantic specification: what they do. No formal notation, so use

comments.

– Semantic specification is a contract.

– Conditions client must satisfy ( preconditions, marked ā€œPre:ā€ in

examples below).

– Promised results ( postconditions).

– Design these to be all the client needs!

– Exceptions communicate errors, specifically failure to meet pre-

conditions.

Histogram Specification and Use

/** A histogram of floating-point values / public interface Histogram { /* The number of buckets in THIS. */ int size ();

/** Lower bound of bucket #K. Pre: 0<=K<size(). */ double low (int k);

/** # of values in bucket #K. Pre: 0<=K<size(). */ int count (int k);

/** Add VAL to the histogram. */ void add (double val); }

Sample output:

void fillHistogram (Histogram H, Scanner in) { while (in.hasNextDouble ()) H.add (in.nextDouble ()); }

void printHistogram (Histogram H) { for (int i = 0; i < H.size (); i += 1) System.out.printf (">=%5.2f | %4d%n", H.low (i), H.count (i)); }