Object Card CardPile SuitePile DeckPile DiscardPile TablePileCardPile has methods such as select, pop, and canTake. select and canTake are overridden by various subclasses - but common behavior is factored into CardPile.
Use of private fields with methods for access - prevents tampering with the field from outside the object (e.g. rank, suite, faceup inside of Card).
Use of final modifier to indicate methods that cannot be overriden in subclasses. (Some controversy about the merits of this.)
Novel forms of composition - field that holds a different kind of part depending on the object's state. (This is the "state" pattern.) Example in book: Frog with a behavior field, which holds either tadpole or adult. Other examples: window object, which holds either a full window or an iconified window; mutable list object, which holds either an empty list or a nonempty list.
Anonymous classes
For objects in Java, assignment copies a reference to the object, but doesn't copy the object. This is also true for passing objects as parameters. (This is the same as in Scheme, when we passed lists as parameters or assigned them to variables.)
"Polymorphic" has a precise meaning in the functional programming community, and we'll study this next in the context of Miranda.
There is unfortunately less agreement in the programming language community at large on the meaning of "polymorphic". We'll adopt the book's definition for object-oriented languages.
A polymorphic function (or method) is one that can be applied to a variety of types. Examples: object.equals(x) -- x can be any type of object.
target.hitBy(b) ... target can be any subclass of PinBallTarget.
Polymorphic variables can hold objects of different classes. Object-oriented languages support bounded polymorphism -- often the variable can't hold just any object, but only objects that are instances of a given class or its subclasses.
Overloading: a function name is overloaded if there are two or more function bodies associated with that name, and we choose the body based on the types of the arguments. Example: + in C.
i+j for integers i and j vs. x+y for floats x and y
Coercion - a separate concept from overloading. Consider i+x for integer i and float x -- we coerce i to float (and use the + for floats).
Another technique: templates (or generics), as in the C++ Standard Template Library. In C++ one can declare a class parameterized with a type T. C++ generates multiple copies of the class for each type of parameter. (Note that this is essential if variables of type T are stored on the stack, since different actual types for T may require different amounts of storage. This isn't an issue in Java since all objects are stored on the heap.)
There are a number of proposals to add a facility for parameterized classes to Java, so that one can for example declare a variable such as
Vector<PinBallTarget> targets = new Vector();Then we can write statements such as
PinBallTarget t; t = targets.elementAt(1);rather than
t = (PinBallTarget) targets.elementAt(1);None of these proposals (as far as I know) use C++ style templates -- rather, there would still be a single class Vector. But we would know at compile time that it held PinBallTargets.
A few examples: