The statement of about this interface relationship is an oversimplification.
The has-a relationship is established between the implementing classes. If interfaces are designed in a way, that all implementing classes always establish a has-a relationship, we can say that there is a has-a relationship between the interfaces.
In case of the Iterator
interface, this is not always the case.
An interface could establish an always existing has-a relationship by declaring at least one method depending on the other object, for example an accessor method. It still can’t enforce implementation classes to implement it in the intended way. E.g. an implementation could implement this method by always throwing an exception. But if an interface’s contract implies a has-a relationship, we may ignore violating implementations.
In case of the Iterator
interface, there is no accessor method but a remove()
method supposed to affect the source collection. But this method has been marked as optional operation and is explicitly allowed to throw an UnsupportedOperationException
. So while it is typical for an iterator implementation to a have a has-a relationship to a collection it was created for, this is not always the case.
A counter-example would be CopyOnWriteArrayList
. When you call iterator()
on it, the returned iterator will have a has-a relationship to the underlying array. So at the iterator’s creation time, both, the collection and the iterator, have a has-a relationship to that array, but when you modify the collection, it will establish a has-a relationship to a new array, so after the modification, the iterator and the collection are entirely decoupled.
Also, not every iterator originates from a collection. For example
Iterator<String> i = Collections.emptyIterator();
Iterator<Integer> i = IntStream.range(0, 10).iterator();
See Collections.emptyIterator()
and BaseStream.iterator()
.
Note that for some cases, most notably immutable collections, we may say that the iterators conceptually have a has-a relationship to the collections because they provide access to their contents, even if implemented in a different way. That’s why the examples above are carefully chosen to counter the statement on a conceptual level, either because there is no collection or the collection is explicitly documented to become decoupled from the iterators on modifications.