Overview
In case you’ve forgotten …
Counter
is an interface that specifies increment
, get
, and
reset
methods.BasicCounter
is a simple implementation of Counter
.DecrementableCounter
is a subclass of BasicCounter
that adds
a Decrement
method.NamedCounter
is a subclass of BasicCounter
that overrides the
toString
method.Let’s consider some issues.
Counter a = new BasicCounter(5); a.increment();
Counter b = new DecrementableCounter(5); b.increment();
b.increment()
? We find the code for
the class. We check whether there’s an increment method. There’s
not, so we look in the super class.Counter c = new DecrementableCounter(5); c.decrement();
DecrementableCounter d = new DecrementableCounter(5); d.decrement();
Counter e = new DecrementableCounter(5); e.toString();
toString
call is fine.toString
?
BasicCounter f = new NamedCounter(5); f.toString();
Can you eliminate a method in a subclass?
Not usually. It violates the assumption that every method available in the superclass is available in the subclass. (That’s what supports subtype polymorphism.)
You can override, you may be able to reduce protection, but you can’t eliminate (and you can’t increase the protection).
What if I really want Counter c = new DecrementableCounter(5); c.decrement();
?
`((DecrementableCounter) c).decrement();
However, if, for some reason,
c
is not a DecrementableCounter, the cast will through an exception. (A ClassCastException)
Philosophy:
Methods:
Approach 1: Very imperative
public interface SchemeList {
public static SchemeList cons(SchemeValue val, SchemeList lst);
public static SchemeValue car(SchemeList lst);
public static SchemeList cdr(SchemeList lst);
public static boolean isNull(SchemeList lst);
} // class SchemeList
Approach 2: More OOP
public interface SchemeList {
/**
* Build a new list by adding val to the front of this list.
*/
SchemeList cons(SchemeValue val);
/**
* Get the first element of the list.
*/
SchemeValue car();
/**
* Get all but the first element.
*/
SchemeList cdr();
} // interface SchemeList
Writing Map
(define map
(lambda (fun lst)
(if (null? lst)
null
(cons (fun (car lst))
(map fun (cdr lst))))))
Philosophy
add
and remove
”
Methods
size
add
take? Getting that right is hard, particularly
if we want to keep things efficient. We’ll leave it for another day.
public interface List<T> {
} // interface List<T>
ArrayList
and then do things like remove(i)
.
public class LinkedSchemeList implements SchemeList {
// +-------+-------------------------------------------------------
// | Notes |
// +-------+
/*
We use a special value, LinkedSchemeList.NULL to represent the
empty list.
*/
// +-----------+---------------------------------------------------
// | Constants |
// +-----------+
public LinkedSchemeList NULL = new LinkedSchemeList(null,null);
// +--------+------------------------------------------------------
// | Fields |
// +--------+
/**
* The value at the front of the list.
*/
public SchemeValue head;
/**
* The rest of the list.
*/
public LinkedSchemeList rest;
// +--------------+------------------------------------------------
// | Constructors |
// +--------------+
/**
* Make a Scheme List with one value.
*/
public LinkedSchemeList(SchemeValue val) {
this.head = val;
this.rest = LinkedSchemeList.NULL;
} // LinkedSchemeList(ScheemValue)
/**
* Make a Scheme List in the traditional way.
*/
private LinkedSchemeList(SchemeValue val, LinkedSchemeList lst) {
this.head = val;
this.rest = lst;
} // LinkedSchemeList(SchemeValue, LinkedSchemeList)
// +---------+-----------------------------------------------------
// | Methods |
// +---------+
/**
* Build a new list by adding val to the front of this list.
*/
LinkedSchemeList cons(SchemeValue val) {
return new LinkedSchemeList(val, this);
} // cons
/**
* Get the first element of the list.
*/
SchemeValue car() {
return this.head;
} // car
/**
* Get all but the first element.
*/
LinkedSchemeList cdr() {
return this.tail;
} // cdr
/**
* Determine if the list is empty.
*/
boolean isEmpty() {
return (this == LinkedSchemeList.NULL);
} // isEmpty
/**
* Convert to a string
*/
public String toString() {
if (this.isEmpty()) {
return "()";
} else if (this.cdr().isEmpty()) {
return "(" + this.head + ")";
} else {
return "(" + this.head + " " + this.cdr().toString().substring(1);
}
} // toString()
} // class LinkedSchemeList
When you finish, you may leave.