UnboundedCounter & UpperBoundedCounterUnboundedCounter: current value (val), increment (up),
decrement (down), retrieve current value (getVal), toString
UpperBoundedCounter: current value (val), upper bound (limit),
bounded increment (up), decrement (down), retrieve current value (getVal),
retrieve limit (getLimit), toString
UpperBoundedCounter, there could also be a
LowerBoundedCounter, and where there's UpperBoundedCounter and LowerBoundedCounter
there could also be …. (By the same token, where there's a UnboundedCounter, there could be
an UpCounter and/or a DownCounter.)
| App.java | App.out |
|---|---|
public class App {
public static void main(String [] args) {
System.out.println("Playing with UnboundedCounter");
UnboundedCounter uc = new UnboundedCounter();
System.out.println("Initially: " + uc);
for (int i = 1; i <= 20; i++)
uc.up();
System.out.println("After 20 up's: " + uc);
for (int i = 1; i <= 3; i++)
uc.down();
System.out.println("After 3 down's: " + uc);
System.out.println(); //---------
System.out.println("Playing with UpperBoundedCounter");
UpperBoundedCounter ubc = new UpperBoundedCounter(10);
System.out.println("Initially: " + ubc);
for (int i = 1; i <= 20; i++)
ubc.up();
System.out.println("After 20 up's: " + ubc);
for (int i = 1; i <= 3; i++)
ubc.down();
System.out.println("After 3 down's: " + ubc);
}
}
|
Playing with UnboundedCounter Initially: A unboundedCounter with value 0 After 20 up's: A unboundedCounter with value 20 After 3 down's: A unboundedCounter with value 17 Playing with UpperBoundedCounter Initially: A upper-bounded counter with value 0 and limit 10 After 20 up's: A upper-bounded counter with value 10 and limit 10 After 3 down's: A upper-bounded counter with value 7 and limit 10 |
| UnboundedCounter.java | UpperBoundedCounter.java |
|---|---|
public class UnboundedCounter {
UnboundedCounter() {val = 0;}
void up() {val++;}
void down() {val--;}
int getVal() {return val;}
public String toString() {
return "A unboundedCounter with value " + val;
}
private int val;
}
|
public class UpperBoundedCounter {
UpperBoundedCounter(int limit) {
val = 0;
this.limit = limit;
}
void up() {if (val < limit) val++;}
void down() {val--;}
int getVal() {return val;}
int getLimit() {return limit;}
public String toString() {
return "A upper-bounded counter with value " + val +
" and limit " + limit;
}
private int val;
private int limit;
}
|

val in both classes could have been done at the point of declaration:
private int val = 0;
UnboundedCounter class
new UnboundedCounter()
UpperBoundedCounter would still require a constructor be written (since a limit must be supplied).
| UnboundedCounter.java | UpperBoundedCounter.java |
|---|---|
public class UnboundedCounter {
UnboundedCounter() {val = 0;}
void up() {val++;}
void down() {val--;}
int getVal() {return val;}
public String toString() {
return "A unboundedCounter with value " + val;
}
private int val;
}
|
public class UpperBoundedCounter {
UpperBoundedCounter(int limit) {
unboundedCounter = new UnboundedCounter();
this.limit = limit;
}
// New methods
void up() {if (unboundedCounter.getVal() < limit) unboundedCounter.up();}
int getLimit() {return limit;}
public String toString() {
return "A upper-bounded counter with value " + getVal() +
" and limit " + limit;
}
//Delegation methods
void down() {unboundedCounter.down();}
int getVal() {return unboundedCounter.getVal();}
private UnboundedCounter unboundedCounter;
private int limit;
}
|

Address class being used as a member by a Person
class and a Company class
Person and Company).
B includes extends C in its class header:
class B extends C {
…
}
class B is said to inherit from class C
B acquires all instance variables and methods of C.
B can define its own instance variables and methods as well
B defines methods identical to those of C
B's method is odentical to that of C
B defines instance variables with the same name
as one in C. While this variable shadowing is legal, it is not
all that useful, and in fact, is not recommended.
C as the parent or superclass and
B as the child or subclass.
B accesses the state/behavior it inherits from C.
private of the parent's instance variable (val)| UnboundedCounter.java | UpperBoundedCounter.java |
|---|---|
public class UnboundedCounter {
UnboundedCounter() {val = 0;}
void up() {val++;}
void down() {val--;}
int getVal() {return val;}
public String toString() {
return "A unboundedCounter with value " + val;
}
/*private*/ int val;
}
|
public class UpperBoundedCounter extends UnboundedCounter {
UpperBoundedCounter(int limit) {this.limit = limit;}
// Overridden methods
void up() {if (val < limit) val++;}
public String toString() {
return "A upper-bounded counter with value " + val +
" and limit " + limit;
}
// new method
int getLimit() {return limit;}
private int limit;
}
|
B does not declare val nor redefine down or getVal
as they are the same logic as in class C
protected| UnboundedCounter.java | UpperBoundedCounter.java |
|---|---|
public class UnboundedCounter {
UnboundedCounter() {val = 0;}
void up() {val++;}
void down() {val--;}
int getVal() {return val;}
public String toString() {
return "A unboundedCounter with value " + val;
}
protected int val;
}
|
public class UpperBoundedCounter extends UnboundedCounter {
UpperBoundedCounter(int limit) {this.limit = limit;}
// Overridden methods
void up() {if (val < limit) val++;}
public String toString() {
return "A upper-bounded counter with value " + val +
" and limit " + limit;
}
// new method
int getLimit() {return limit;}
private int limit;
}
|
super keyword acting as qualifier.
| UnboundedCounter.java | UpperBoundedCounter.java |
|---|---|
public class UnboundedCounter {
UnboundedCounter() {val = 0;}
void up() {val++;}
void down() {val--;}
int getVal() {return val;}
public String toString() {
return "A unboundedCounter with value " + val;
}
private int val = 0;
}
|
public class UpperBoundedCounter extends UnboundedCounter {
UpperBoundedCounter(int limit) {this.limit = limit;}
// Overridden methods
void up() {if (getVal() < limit) super.up();}
public String toString() {
return "A upper-bounded counter with value " +
getVal() + " and limit " + limit;
}
int getLimit() {return limit;}
private int limit;
}
|
getVal provides access to the value and again, we use super
to access the superclass' up method
super keyword acting as qualifier.

extends clause, there's no sign of the
inherited class (superclass) in the definition of the inheriting class (subclass).
UnboundedCounter
UpperBoundedCounter
UnboundedCounter UpperBoundedCounter
UpperBoundedCounter is-a UnboundedCounter,
an UpperBoundedCounter object can appear wherever a UnboundedCounter object can appear
UpperBoundedCounter is a subclass of
UnboundedCounter, it inherited ALL UnboundedCounter's state and behavior, and thus, any method or field access
that can be performed on a UnboundedCounter object can be performed on an UpperBoundedCounter object as well.
UpperBoundedCounter may contain state/behavior tht UnboundedCounter does
not (e.g. limit and getLimit), thus a UnboundedCounter object cannot appear in
a context expecting an UpperBoundedCounter.
UnboundedCounter uc; UpperBoundedCounter ubc = new UpperBoundedCounter(10); uc = ubc;or equivalently (but possibly more confusing):
UnboundedCounter uc = new UpperBoundedCounter(10);but not
UpperBoundedCounter ubc = new UnboundedCounter(); // illegal
| App2.java | App2.out |
|---|---|
public class App2 {
public static void main(String [] args) {
UnboundedCounter [] counters = {new UnboundedCounter(), new UpperBoundedCounter(10)};
for (int i = 0; i < counters.length; i++) {
System.out.println("Playing with counters[" + i + "]:");
doIt(counters[i]);
}
}
static void doIt(UnboundedCounter unboundedCounter) {
System.out.println("\tInitially: " + unboundedCounter);
for (int i = 1; i <= 20; i++)
unboundedCounter.up();
System.out.println("\tAfter 20 up's: " + unboundedCounter);
for (int i = 1; i <= 3; i++)
unboundedCounter.down();
System.out.println("\tAfter 3 down's: " + unboundedCounter);
}
}
|
Playing with counters[0]: Initially: A unboundedCounter with value 0 After 20 up's: A unboundedCounter with value 20 After 3 down's: A unboundedCounter with value 17 Playing with counters[1]: Initially: An upper-bounded counter with value 0 and limit 10 After 20 up's: An upper-bounded counter with value 10 and limit 10 After 3 down's: An upper-bounded counter with value 7 and limit 10 |

UnboundedCounter uc; UpperBoundedCounter ubc;it is clear that the type of the variable
uc is the class UnboundedCounter (and similarly for the type
of ubc.
UnboundedCounter uc = new UnboundedCounter(); UpperBoundedCounter ubc = new UpperBoundedCounter(12);while we can tell the types of the objects reference by
uc (it's a UnboundedCounter object) and y ubc
(an UpperBoundedCounter object), it's important to realize that the objects are not actually created until we execute
the program (and actually call the new operator).
up on UnboundedCounter and UpperBoundedCounter objects manifested
completely different behavior
toString
UnboundedCounter objects can
operate — without any further modification — on any object belonging to a subclass of UnboundedCounter
UpperBoundedCounter into a project does not require any recompilation
or other deployment of any existing code that works with UnboundedCounter.
UpperBoundedCounter despite the fact that
the method was written a month ago, and UpperBoundedCounter just coded this morning:
void clear(UnboundedCounter unboundedCounter) {
while (unboundedCounter.getVal() > 0)
unboundedCounter.down();
void jumpUp(UnboundedCounter unboundedCounter, int howMany) {
for (int i = 1; i <= howMany; i++)
unboundedCounter.up();
}
will invoke the proper up method depending upon whether a UnboundedCounter or
UpperBoundedCounter object is passed to jumpUp (ensuring the integrity of the
limit for the latter).
UnboundedCounter
in our example) is a class rather than an interface.
is-arelationship between subclass and superclass, and the consequential Substitution Principle, tells us that an object
of a subclass can always appear in any context that an object of the superclass can appear in.
UnboundedCounter uc = new UpperBoundedCounter(12);
UnboundedCounter uc; UpperBoundedCouner ubc; … uc = ubc;
UnboundedCounter) reference to
that of a subclass (UpperBoundedCounter)
UpperBoundedCounter ubc = new UpperBoundedCounter(10); UnboundedCounter uc = ubc; // perfectly legal — upcast ubc = uc; // shouldn't this be legal? —uccontains a reference to anUpperBoundedCounterobject
UnboundedCounter uc = new UnboundedCounter(); UpperBoundedCounter ubc = uc; // should be illegal —uccontains a reference to aUnboundedCounterobject
UnboundedCounter uc;
Scanner keyboard = new Scanner(System.in);
System.out.print("c or u? ");
String choice = keyboard.next();
if (choice.equals("c")
c = new UnboundedCounter();
else
uc = new UpperBoundedCounter(12); // legal upcast
UpperBoundedCounter ubc = uc; // legal? illegal?
UpperBoundedCounter ubc = (UpperBoundedCounter)uc; // legal? illegal? ... won't know until runtime
ClassCastException
class Name {
Name(String first, String last) {
this.first first;
this.last = last;
}
…
private String first, last;
}
Note that one must supply first and last names when creating a Name object.
Name name = new Name("Gerald", "Weiss");
Now, consider a subclass FormalName that inherits from Name
and adds a salutation:
class FormalName extends Name {
…
private String salutation;
}
FormalName is-a Name as well, and thus when one creates a FormalName
you are also (implicitly) creating a Name object and thus need to supply a first/last name as
well as the salutation, e.g.:
FormalName formalName = new FormalName("Mr.", "Gerald", "Weiss");
this gives us the constructor:
FormalName(String salutation, String first, String last) {
this.salutation = salutation;
…
}
The question becomes, how do we initialize the instance variables of the Name class?
FormalName's constructor cannot/should-not do it:
first andlast may be declared private (as they are
above).
first andlast are not the responsibility of FormalName;
they belong to Name
super:
FormalName(String salutation, String first, String last) {
super(first, last);
this.salutation = salutation;
}
in the context of constructors, super is used by a subclass to pass constructor arguments
to the superclass
this in the constructor but that is to pass arguments between overloaded
constructors within the same class.
super must be the first line of code in the constructor
FormalName had been defined using composition instead of inheritance:
class FormalName {
FormalName(String salutation, String first, String last) {
name = new Name(first, last);
this.salutation = salutation;
}
…
private Name name;
private String salutation;
}
name is an actual reference variable under FormalName's control
and must have an object created and its reference assigned to name
Name methods must be repeated as delegation methods in FormaName
Collection interface:
interface Collection {
boolean add(int value);
boolean remove(int value);
int size();
boolean isEmpty();
}
As we've discussed numerous times, isEmpty can leverage off size:
boolean isEmpty() {return size() == 0;}
i.e., we really don't need for every implementing class to write its own copy of isEmpty.
However, interfaces do not permit method bodies, and we WANT our Shape interface to include an isEmpty
method. We can get what we want with an abstract class
abstract class AbstractCollection implements Collection {
//public abstract boolean add(int value); // unnecessary
/public abstract boolean remove(int value);
//public abstract int size();
public boolean isEmpty() {return size() == 0;}
}
AbstractCollection above, one need not include the method header for size
abstract keyword (and public) in the method header if this is an interface method.
abstract keyword in the method header.
AbstractCollection thus no longer need to define isEmpty.
AbstractCollection (i.e., a class that only imeplements some of the methods of the interface it is 'implementing') is sometimes referred to as a
skeletal or partial implementation
UpCounter, DownCounter, UnboundedCounter,
UppperBoundedUpCounter, UppperBoundedCounter, LowerBoundedDownCounter,
LowerBoundedCounter, BoundedCounter?