Source: CS61B — ArraySet lecture example (Iterable/Iterator design)
for (T x : obj) Actually Work?Java's for-each loop looks like magic, but it's just syntactic sugar. The compiler needs some guaranteed protocol that any class can implement so that for (T x : obj) works on it — whether obj is an ArrayList, a HashSet, or a custom ArraySet.
That guaranteed protocol is split into two separate interfaces, each with a distinct job.
Iterable<T> — A Promise, Not a Mechanismpublic interface Iterable<T> {
Iterator<T> iterator();
}
Iterable has exactly one method. Implementing it means: "objects of this class can be looped over." It does not do any of the actual walking-through-elements work itself — it only promises to produce something (an Iterator) that can.
ArraySet<T> implements Iterable<T> → ArraySet is declaring it can be used in a for-each loop, and as proof, it must supply a working iterator() method.
Iterator<T> — The Protocol for Walking Through Elementspublic interface Iterator<T> {
boolean hasNext();
T next();
}
This is the interface that actually defines "how to walk." It requires two things: can you tell me if there's a next element, and can you give me the next element (advancing your internal pointer as you do so).
Key design insight: Iterable and Iterator are deliberately two different objects, not one. The collection (ArraySet) does not itself track "how far along the traversal we are" — that job belongs to a separate, freshly-created Iterator object. This separation is what allows two independent for-each loops over the same ArraySet to run at once without interfering (e.g. a nested loop iterating the same set twice) — each call to .iterator() hands out a brand-new object with its own independent position counter.
ArraySetIterator — The Concrete Implementation, as an Inner Classprivate class ArraySetIterator implements Iterator<T> {
private int wizPos;
public ArraySetIterator() {
wizPos = 0;
}
public boolean hasNext() {
return wizPos < size;
}
public T next() {
T returnItem = items[wizPos];
wizPos += 1;
return returnItem;
}
}
This is where Iterator<T> actually gets implemented for ArraySet. Two things matter here:
ArraySet instance's private fields (items, size) — no need to pass them in through a constructor. That's why items[wizPos] and wizPos < size just work without any extra plumbing.wizPos, completely separate from ArraySet's own size field. size = how many elements the ArraySet holds (a property of the set). wizPos = how far this particular traversal has progressed (a property of one Iterator instance). Confusing these two is the most common conceptual mistake when first learning this pattern.for (int i : aset) {
System.out.println(i);
}
The compiler expands this into: