Comp 271 Week 1
Damen 339, 4:15-5:30+5:30-6:20 Tues, 4:15-5:30 Thurs

Welcome

BlueJ, maybe eclipse later.

Text: Bailey, online. Note pun on root-7 versus route-7.

What the heck is a data structure? Any structure that involves data! Generally, data that is in addition to that needed to implement the structure itself.

More specifically, it can be a general-purpose container, like a list, or an application-specific structure. Note, however, that it is usually a good idea to try to make application-specific structures into something more general, if only to separate conceptually the app-specific part from the general part.

In Java, we implement these with classes. The class interface is all the client programmer needs to know; the implementation we can change at will.

Classes let us:

General-purpose container classes typically involve type parameters, called generic classes in java. The parameter type is enclosed in angled brackets, a tradition that comes from the C++ notion of a template.
    ArrayList<Integer> theCounts;       // why not ArrayList<int> ???
    ArrayList<Message> mailbox;

Note that angles do not quite work as intended as delimeters; two closing angle brackets >> are read as the single token '>>', used for right-shift. Thus, if we want a list of lists:
    ArrayList<ArrayList<Cell>> grid;      // WRONG
we can't do it that way; we have to add a space:
    ArrayList<ArrayList<Cell>  > grid;

The central idea of a class is that we can define the public interface however we want, and keep the internals to ourselves. Thus, outside users have only the interface we provide. If there is a length field, or a pointer to the first cell, then if we keep the field private we need not fear that some client programmer will modify it and thus make a mess of it.

Class rule #1: all class data fields should be private. This way, you who writes the class has full control over its internal structure. Bailey prefers protected, but there is little justification for that.

Note that protected is generally considered to be a bad idea, despite Bailey's enthusiasm; we will use private instead!

Who are we keeping data private (or protected) from? The idea is that you are the class implementor, and some other programmer (possibly you at a later date) is the client programmer. See Bailey §1.9.

String

Example 1: Bailey, p 7: two ways of implementing a string. Possible interface:
    charAt(int), length()
Note that how we implement the class has no bearing on the interface!
Other examples of objects:

Point

Here is a pretty minimal class. We have a constructor and two (field) accessors. There is no mutator at all; if you want to move a point, you have to create a new one. Note the convention that fields begin with _; many find some such convention helpful.

class Point {
    private int _xcoord;
    private int _ycoord;
    public Point(int x, int y) {
          _xcoord = x;
          _ycoord = y;
    }
    public int getX() {return _xcoord;}
    public int getY() {return _ycoord;}
}

Note the methods, which are field accessors.

Ratio example, Bailey p 8

We're creating a class to represent rational numbers. Note especially the gcd() and reduce() methods. Also note that there are no field mutators (though there are field accessors) even though we do allow the value to change; the object acts as a whole.

Thursday

Loops

Suppose we have ArrayList<String> AL, that has data in it. How can we print out the entries?

1. while loop

int i=0;
while (i<AL.size()) {
    System.out.println(AL.get(i));
    i++;
}
For a while loop, the loop variable 'i' must be declared before the while.

2. for loop ("classic for")

for (int i=0; i<AL.size(); i++)
    System.out.println(AL.get(i));
Note that I've chosen to declare i within the loop here. You can do that or else declare the loop variable as in the while loop example above.

3. for-each loop

for (String s : AL)
    System.out.println(s);
Note that we don't have get(i) here; the for-each loop uses the String variable s as the "loop variable". Note that s must be declared within the loop, as shown. Java takes care of assigning to s each element of AL, in turn.

4. Iterator loop

Iterator<String> it = words.iterator();
while (it.hasNext())
     System.out.println(it.next());
This is an iterator. Iterators were sort of a predecessor to the for-each loop. Both Iterators and for-each work for any Collection, not just ArrayList. Why would you use an Iterator, rather than the for-each loop? There are times when the loop structure isn't so simple; consider a single loop that takes elements from two lists, one from each for each loop pass. You can't do that with a for-each loop, because the for-each loop would go through just one of the lists.

What an iterator is is a precise way of keeping track of the "current position" in a list. As we saw in Lab 0, the actual object representing the iterator has two pieces: a reference to the original list, and also our current position.

Back to the Ratio class


The gcd() method is recursive: it calls itself. How could we create an iterative (looping) version? Here's one possibility.
// pre: a>=0, b>=0, a>0 or b>0
int gcd(int a, int b) {
    while (a>0 && b>0) {
       if (a>=b) a = a % b;
       else b = b % a;
    }
    if (a==0) return b; else return a;



Finally, note the toString() method. For now, you can call this explicitly whenever needed. However, note that toString() works more generally; it is our first example of inheritance. The master parent class Object defines toString(); any subclass can override that definition, as is being done here. In println(), when something needs to be printed then toString() is called implicitly; the rules of inheritance ensure that the most specific version of toString is the one to be invoked.

Student and BankAccount examples

Bailey includes a BankAccount example on page 11. A related example might be a Student class, with fields for name, address, and other personal examples. Each of these classes comes equipped with a nearly full range of field accessors that return individual fields, and field mutators that update them. Note, however, that there is no mutator for the account field; we do not anticipate changing that. Also, there is no mutator for balance; we can deposit() and withdraw() money, but we can't just set the balance to whatever we want. In a real banking system, this helps the programmers verify that when money is deposited, it has to come from somewhere else.

Notice also the pre- and post-conditions for the methods. These are a good idea, though they take some getting used to and "trivial" preconditions can be inscrutable.

Also note the .equals() method.

The Student and BankAccount examples can be deceptive, as they tend to focus primarily on fields. In this sense they are more like database records than java classes. Java classes tend to focus on methods. (The class Point also is dominated by its fields.) Compare with the class Ratio, with nontrivial methods reduce() and gcd(). (The BankAccount class might potentially have some "nontrivial" methods added to move funds around that verified the money was there, but this simple example doesn't do that.)

Association

The Association class in §1.5 is simply a "pair", <key,value>, where we provide accessors for both fields but a mutator only for the value. That is, we do not allow ourselves to change the key (however, we can create a new Association object with a new key). We also provide an equals() method.

Note that there are two constructors for this class. Furthermore, the single-parameter constructor calls the two-param ctor; if we restructure the underlying implementation only the two-param ctor needs to be rewritten.

How does Association differ from Point?

Stack

The Stack class, with specific methods push(), pop(), and isEmpty(), is sort of the canonical example of an Abstract Data Type, that is, a class where the focus is on representing a "thing" (as is usually the case). A stack can be implemented as an array, but we have no access to the top element except through pop(), and no access to the middle elements at all. Alternatively, we could change the implementation to that of, say, "linked list", and the class users would be unaffected. Note that push() and pop() do not simply perform individual field updates.

Finding something to do with the stack is harder; why would you need that very specific last-in, first-out (LIFO) access? There are lots of examples from system design and programming-language design, but they tend not to be trivial. One straightforward example is to confirm that a line consisting of ()[]{} has all the braces in balance. The algorithm is as follows:
    if you encounter an opening symbol, (, [, or {, push it.
    if you encounter a closing symbol, ), ], or }, pop what is on the stack and verify the two correspond.
    when you get to the end of the input, verify that the stack is empty.

Note that generally popping something off an empty stack is an error, so that you should check with isEmpty().

the Rect class

Note the drawOn() precondition that the window is a valid one. Note also the relatively rich set of operations. Note also that for left() and width() the accessor and the mutator have the same name! Java distinguishes by the presence of the parameter. Some people find this approach helpful; others find it too confusing by half. The most common naming strategy is probably left() for the accessor and setLeft() for the mutator.

Normally, drawing a Rectangle is a primitive operation in the graphics library.

WordList

This is in §1.6; the main issue here is the example in §1.8 of an Interface. On p. 20 is the basic interface of WordList as a standalone class. On pp 22-23, an interface Structure is defined and WordList is then declared to implement that interface:
    public class WordList implements Structure

A class can extend just one parent class, but can implement multiple interfaces. In particular, a WordList could extend, say, StrList, and also implement Structure.

StrList

(Done Tuesday, mostly) For Lab 0 we'll look at a list class, StrList. It is intended to work like ArrayList<String>. Note first of all that we are not making use of a "type parameter" like String; our class will only work with Strings. The type parameter in ArrayList makes that into what is called in Java a "generic class"; we'll get to those in Chapter 4. For now, note that if we ever want to change to a list of some other type we have a fair amount of editing to do.

get() and set() work as in an ArrayList, except they do not throw exceptions for out-of-range values.

Note that get(n) for n out of range returns null. This would work for any object type.

add(String s) needs some work. You are to fix things so that, if there's no room, then new room is created, and everything is moved to the larger array, and then the add() carries on as usual.

Thursday:

Demo with the inspector and a real ArrayList: sizes are 10, 16, 25, 38, ...
Demo: arraylisttest (I have not put this online), with methods addOne(Str s) and addSome(int count, Str s).
Here is the actual ArrayList.java source code; let's find where the numbers 10, 16, 25, .. come from.

add(String [] sa) would be pretty easy to add too. You would probably want to resize the underlying array things[] only once.

Iterators

Note that my StrList class has a method iterator(), that creates and returns an Iterator object. Iterator is an interface, not a class, which simply means that it guarantees no data itself (and also that the underlying object can be any class type). The actual class type of the Iterator objects is MyIterator, which is a private class (it's not essential that this be private, but it clarifies our intent).

Here's an ArrayList version of an iterator:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

public class iterdemo {
    public static void main(String[] argv) {
        Random r = new Random();
        ArrayList<Integer> a = new ArrayList<Integer>();
        for (int i = 0; i<30; i++) a.add(r.nextInt());   // fill w. random values
        Iterator it = a.iterator();
        while (it.hasNext()) {
           System.out.println(it.next());
        }
    }
}

The iterator is created with a.iterator(), and then used with hasNext() and next().

Part of the lab has you create a "reverse iterator". This should emphasize that what the next() method does is entirely up to the programmer.