0

couldn't help but feel the title is kinda vague, sorry about that. I couldn't describe it better.

I'll get a little more into detail; I'm trying to figure out how to get an iterator working the way I want it to outside of the class it's implemented in. I couldn't manage to find any information on my problem. This is part of an assignment for University, AlphaTest.java should be left as is.

I have a class, Alpha, which holds a class which follows the doubly linked list principle, Bravo. Bravo holds the link to the previous and next instance in the list.

I want to be able to iterate through the linked list with an iterator implemented in the Alpha class so that I can easily go through each instance using a for loop like this: for(Bravo b: alphaInstance) {...}.

I got this to work as intended within the Alpha class itself, but once I try the same outside of the Alpha class, in AlphaTest for example, it doesn't work as intended. Once I try that I'm hit with the following error:

Error:(220, 23) java: incompatible types: java.lang.Object cannot be converted to models.Bravo

It wants me to instantiate the instance as an Object like so:

for(Object o: alphaInstance) {...}

I could of course cast the object to Bravo. But that's not part of the assignment.

See code below to see what's going wrong. The problem can be found in AlphaTest.java.

Alpha.java

class Alpha<E extends Bravo> implements Iterable<Bravo> {
    Bravo head;

    public Alpha(Bravo head) {
       this.head = head;
    }

    public void example() {
       for(Bravo b: this) {
          // This works, it's succesfully recognized as an instance of Bravo.
       }
    }

    @Override
    public Iterator<Bravo> iterator() {
    return new BravoIterator(this.head);
    }

    private class BravoIterator implements Iterator<Bravo> {
       private Bravo currentBravo;

       public BravoIterator(Bravo head) {
          this.currentBravo = head;
       }

        @Override
        public boolean hasNext() {
            return this.currentBravo != null;
        }

        @Override
        public Wagon next() {
            Bravo data = this.currentBravo;
            this.currentBravo = this.currentBravo.getNextBravo();
            return data;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

    }
}

AlphaTest.java

{...}

    @BeforeEach
    private void setup() {
        // Assume this is a doubly linked list
        Bravo bravo = new Bravo(...);
        

        instanceOfAlpha = new Alpha(bravo);
    }

    public T1_checkImplementationOfIterableInterface() {
       for(Bravo b: instanceOfAlpha) {  // <---------------------------------------------[This is the problem]
          // This does not work, it expects an instance of Object.
       }
    }

{...}
Marble
  • 79
  • 2
  • I think it does, I took a good look at AlphaTest.java and I realised that the prof. didn't actually make use of the generic in Alpha.java. Once I instantiated it with a generic of a class which extends Bravo it worked. – Marble Sep 21 '20 at 14:02

1 Answers1

1

You've mischaracterized the error.

What's happening is that instanceOfAlpha is an expression whose type ends up being Alpha - you've elided your definition of this variable, but it seems obvious enough, as you're creating the value for this variable with a raw type as well. Alpha would be a so-called raw type - a type that has type parameters, but where the parameters are missing.

The thing is, raw types are a tad odd: Once you go raw, everything about it is raw, even things that aren't using any of the generics you failed to specify. Thus, the iterator() method of your raw Alpha expression returns a raw Iterator (you'd think it returns an Iterator<Bravo>, but it does not). And therefore, iterating over it returns basic Objects. And therefore, your for loop is broken; for (Object b : instanceOfAlpha){} would compile; for (Bravo b : instanceOfAlpha){} won't.

The fix is generally that when the compiler throws warnings in your face that you shouldn't just go ¯_(ツ)_/¯ I don't know what those mean so I'll just be like the 3 monkeys and just wish that whatever I don't understand is hopefully utterly irrelevant.

It's not. The real fix is: Fix your generics so you don't get these warnings.

You haven't pasted enough code to tell you exactly what you need to do here; probably make instanceOfAlpha be declared as a Alpha<?>. More generally, your first paste (of your Alpha class) looks like you just don't get how generics works; most of the places that mention Bravo in that should have been using E instead. generics is a little tricky; perhaps you want to just opt out altogether. Get rid of the <E extends Bravo> part entirely, and then leave the rest pretty much as is, that would also fix things.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72