Can I extend Iterator to allow access to encapsulated inner class fields?

688 views Asked by At

I'm frustrated, trying to add methods to a custom iterator.

For an assignment in my second quarter Java class, we are supposed to implement, from scratch, a linked list. No problem: I have created an outer class to implement the linked list and a static private inner class to implement the individual nodes, to encapsulate them, hidden from any client program.

The nodes in this linked list are to have two distinct next fields (one for names and another for places). Following one of the next fields will take me through all the nodes by one path; following the other next field will take me another route. (Think two distinct alphabetical orders, depending on name or on place.) No problem: to iterate through the nodes, following the names or following the places, I created two custom iterators. One abstract class implements Iterator< Node > and common code, and two inner classes implement the custom code for each iterator through either the nextName field or the nextPlace field.

The next() and hasNext() methods work beautifully, giving customized results depending on whether I've instantiated a name or a place iterator.

These nodes also contain data I want to print to the console and save in a file. The nodes were deliberately encapsulated inside the list class to protect them from rogue use by a client program. I thought to extend my iterators by adding accessor methods, such as getName() and getPlace() methods. It's why I took the extra step of creating an abstract class, rather than having my custom iterators directly implement Iterator.

But it's not working. I get "cannot find symbol" when I call itr.getName() from the client. The closest answer I've seen is here but I still get "cannot find symbol."

Here's a synopsis of my code:

import java.util.Iterator;

public class MyList implements Iterable {

    // ...

    public Iterator nameIterator() {
        return new NameIterator( this );
    }

    public Iterator placeIterator() {
        return new placeIterator( this );
    }

    public abstract class NodeIterator implements Iterator< Node > {

        public NodeIterator( MyList list ) { ... }

        public boolean hasNext() { ... } // this appears to work fine

        public String getName() { ... } // this can't be seen by the client

        public String getPlace() { ... } // this can't be seen by the client

    }

    private class NameIterator extends NodeIterator {

        public NameIterator( MyList list ) {
            super( list );
            ...
        }

        public Node next() { ... }

    }

    private class PlaceIterator extends NodeIterator { ... } // same as NameIterator with custom code

    private static class AttractionNode {
        public String  name;
        public String  place;

        public Node  nextName;
        public Node  nextPlace;

        // ...
    }
}

I want the client code to be able to run:

    System.out.println( "\nBy names: " );
    Iterator itr = placesToGo.nameIterator();
    while( itr.hasNext() ) {
        itr.next();
        System.out.println( itr.getName() ); // gives me "cannot find symbol" error
        // System.out.println( itr.next() ); // works fine, alone
    }

Sorry for the long question. It's my first here, and I'm still figuring out what exactly my problem even is.

2

There are 2 answers

1
AdamSkywalker On BEST ANSWER

After reading discussion in comments, I suggest you to use IDE that can help you to resolve compile errors, like Intellij IDEA, for example.

Short review of your problems:

As was said, your List methods that return custom iterators, must have a concrete return type like NameIterator or PlaceIterator.

I applied both fixes -- declaring itr as a NameIterator in the client code; returning a NameIterator when nameIterator() is called. Sigh. Now "cannot find symbol" has moved to point to the NameIterator itr declaration.

It seems, that compiler does not see your inner NameIterator class. To use inner class from outside the outer class, you should specify outer class name as well:

MyList.NameIterator itr = myList.nameIterator();

Or import this class:

import your.package.MyList.NameIterator;
0
AudioBubble On

nameIterator() must return NameIterator instead of Iterator<Node>.

public NameIterator nameIterator() {
    return new NameIterator( this );
}

And the client code must use NameIterator instead of Iterator<Node>.

    System.out.println( "\nBy names: " );
    NameIterator itr = placesToGo.nameIterator();
    while( itr.hasNext() ) {
        itr.next();
        System.out.println( itr.getName() );
    }