250 likes | 387 Vues
This guide explores advanced techniques in Java, focusing on reversing a linked list without allocating new objects and the implementation of iterators. We discuss the significance of inner classes in creating iterators that keep track of their parent container, allowing for more flexible and efficient iteration methods. Key problems addressed include list reversal and the creation of a generic interface for iterators. Additionally, we cover how to efficiently decide whether a tree structure can produce specific traversal results based on two lists.
E N D
Section 7 topics • Prelim review. • Inner classes. • Iterators.
Prelim review, problem 1 C1 I1 C2 I2 C3
Prelim review, problem 1 C1 obj1 obj3 = obj2 obj2 = obj1 I1 i1 C2 obj2 i1 = obj3 obj3 = obj1 I2 i2 C3 obj3 i2 = obj1
Prelim review, problem 4 • Reversing a list without allocating new objects. • Use iteration! • Keep track of the current object and the previous object.
Prelim review, problem 4 static public ListCell reverse(ListCell f) { ListCell current, previous; // check two base cases if (f == null) return null; if (f.getNext() == null) return f; // set the initial values of the // variables current = f.getNext(); previous = f; previous.setNext(null); while (current != null) { ListCell temp = current.getNext(); current.setNext(previous); previous = current; current = temp; } return previous; }
Prelim review,problem 6 • Interesting (?) question: find a general algorithm which given two lists decides whether there is a tree, which postorder traversal results in the first list, and preorder in the second one. • Even more interesting (??) question: Find one which is efficient.
Iterators • Abstract concept: Containers. • Instances: Arrays, trees, sets, lists, datasets itp. • Associated concept: Iterators. • Used to iterate over a container. • I.e. suppose we want to find out the number of the elements in any container.
Iterators • We would like to have a way to write even more generic functions. • I.e. suppose we want to find out the number of the elements in any container. • Or given a container, create a list of its elements.
Iterators • With a list: int elems(ListCell l) { int i = 0; for (ListCell q = l; q != null; q = q.getNext()) { i++; } return i; }
Iterators • With a tree: int elems(TreeCell t) { if (t == null) return 0; return elems(t.getLeft()) + elems(t.getRight()) + 1; }
Iterators • More general solution - define an interface of Iterator: interface Iterator { boolean hasNext(); Object next(); void remove(); }
Iterators • Now we can write (note the usage, which is typical:) int elems(Iterator i) { Object o; int res = 0; while (i.hasNext()) { o = i.next(); // here we could do something with o res++; } return res; }
Iterators • How to implement them? • Consider the class: class ArrayIntContainer { public int a[]; ... }
Iterators • First idea: Make the container class implement the iterator. class ArrayIntContainer implements Iterator { public int a[]; private int counter; public boolean hasNext() { return counter < a.length; } public Object next() { return new Integer(a[counter++]); } ArrayIntContainter() { counter = 0; } } • Disadvantages?
Iterators • First idea: Make the container class implement the iterator. class ArrayIntContainer implements Iterator { public int a[]; private int counter; public boolean hasNext() { return counter < a.length; } public Object next() { return new Integer(a[counter++]); } ArrayIntContainter() { counter = 0; } } • Disadvantages: No way to reset the counter. Only one iterator per object.
Iterators • Second idea: Create the adapter class, used only for iteration, which keeps the reference of the container object. class AIterator implements Iterator { private ArrayIntContainer aic; int counter; AIterator(ArrayIntContainer c) { aic = c; counter = 0; } public boolean hasNext() { return counter < aic.a.length; } ... } • Disadvantages?
Iterators • Second idea: Create the adapter class, used only for iteration, which keeps the reference of the container object. class AIterator implements Iterator { private ArrayIntContainer aic; int counter; AIterator(ArrayIntContainer c) { aic = c; counter = 0; } public boolean hasNext() { return counter < aic.a.length; } ... } • Disadvantages: Doesn’t work if a is private. Too large separation can result in incosistent code.
A solution! • A good solution is to use inner classes.
Inner classes • Important features: • We can declare a class inside another class. • We can return an instance of inner class to the outside world. • The instance of the inner class keeps track of the outer class object.
Inner classes class A { private int a; A() { a = 0; } public void seta(int q) { a = q; } public class B { public int geta() { return a; } } public B getB() { return new B(); } public void method() { A a = new A(); A.B b = a.getB(); a.seta(20); System.out.println(b.geta()); } }
Back to the future^O Iterators • Inner classes allow us to implement iterators in a nice way. class ArrayIntContainer { private int a[]; private class AICIterator implements Iterator { private int counter; public boolean hasNext() { return counter < a.length; } public Object next() { return new Integer(a[counter++]); } AICIterator() { counter = 0; } } public Iterator getIterator() { return new AICIterator(); } }
Generic functions interface HasIterator { Iterator getIterator(); } int elems(HasIterator i) { ... }
Generic functions interface HasIterator { Iterator getIterator(); } int elems(HasIterator c) { Iterator i = c.getIterator(); int res = 0; while (i.hasNext()) { res++; i.next(); } return res; }
Fancy stuff • Anonymous inner classes public Iterator getIterator { return new Iterator { public boolean hasNext() { ... } ... }; } • Saves the namespace.
Things to remember • General pattern of implementing adaptors - things which use class data, but are somehow separate from the class.