• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Rob Spoor
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Junilu Lacar
  • Tim Cooke
Saloon Keepers:
  • Tim Holloway
  • Piet Souris
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Frits Walraven
  • Himai Minh

What Implementation of an Abstract Interface Method is Executed?

 
Ranch Hand
Posts: 113
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Kindly refer to the following code segment for the question I ask here:
Since the hasNext() and next() methods of interface Iterator<T> are abstract methods of this interface, what implementations of these methods are executed when an instance of the interface invokes the methods on lines 7 and 9?
 
Marshal
Posts: 26750
81
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You asked an ArrayList to give you an Iterator. So it gave you an Iterator, more specifically an instance of some class which implements Iterator.

The API documentation, of course, doesn't tell you the name of that class, it only provides some information about how it works. But for sure the class does exist, although it is probably not a public class; if you wanted you could print out its name. Like so:


 
Bartender
Posts: 1059
33
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I will be saying essentially the same thing as Campbell, but using different words, so the chances that either of our answers will "click" or that either of our answers will confuse you will double.  

Every class that implements Collection is guaranteed and required to provide a working implementation of:
Iterator<E> iterator()
Returns an iterator over the elements in this collection.

So whether you are working with a List, Set, Queue, etc. there will be one you can call, it is decided to be legal at compile time.
Additionally, it will have working implementations of .hasNext() and .next()

The list given in the Javadocs specifies the following sub-types of Collection:
All Known Subinterfaces:
BeanContext, BeanContextServices, BlockingDeque<E>, BlockingQueue<E>, Deque<E>, EventSet, List<E>, NavigableSet<E>, Queue<E>, Set<E>, SortedSet<E>, TransferQueue<E>
All Known Implementing Classes:
AbstractCollection, AbstractList, AbstractQueue, AbstractSequentialList, AbstractSet, ArrayBlockingQueue, ArrayDeque, ArrayList, AttributeList, BeanContextServicesSupport, BeanContextSupport, ConcurrentHashMap.KeySetView, ConcurrentLinkedDeque, ConcurrentLinkedQueue, ConcurrentSkipListSet, CopyOnWriteArrayList, CopyOnWriteArraySet, DelayQueue, EnumSet, HashSet, JobStateReasons, LinkedBlockingDeque, LinkedBlockingQueue, LinkedHashSet, LinkedList, LinkedTransferQueue, PriorityBlockingQueue, PriorityQueue, RoleList, RoleUnresolvedList, Stack, SynchronousQueue, TreeSet, Vector


(Collection itself is a sub-interface of Iterable, so there are even more things you can get an Iterator<T> from, that are not necessarily Collection type.)

The magic comes from your call:
Iterator<Integer> i = a.iterator();

As long as a refers to anything that implements or extends Iterable that line will compile, and have the same interface!
At Runtime, using the General/Universal rules of Polymorphism, you will get an Iterator<Integer> from whatever the most-derived overriden version is for the actual, run-time type of a at the moment that line executes.  Depending on the program logic, if there are several different actual runtime types that a may refer to, some might be default methods from the Iterable or Collection interface, something that overrides these in an Abstract Class along the way, or perhaps even overridden in the actual Concrete Class involved.

It is the heart of the Magic of Polymorphism that you do not need to be concerned as a user of the interface, exactly which of these is the case.
This is the reason that we code to Interface, not to Implementation.

Now, if you are curious, the actual code that will be called in the simple example you provided, as Campbell explained in far fewer words, is determined at this line:
a = new ArrayList<Integer>();

If you were very curious, you could step into the code at the site of the calls in question, or slightly correcting Campbell's answer, you could write the line:
System.out.println(i.getClass().getName()); // i will give you the type of the iterator, which came from, but is not the same type as a

However, it is important to note that it is not required to know this, and many effective, efficient productive programmers would say "Yeah, whatever, I don't care, that isn't my business here, I am using an implementation of an Interface, for all I know the actual answer will change two more times the next two times I upgrade Java, but my code will work all along, as I have no dependence in my code upon that answer!"

So far, the whole discussion applies pretty much to making use of interfaces using classes that implement them in Java, and to a near approximation, any Object-Oriented language.

Now I will mention something specific to the example you gave.

Any interface that extends, and any class that implements Iterable, will give you not just the methods you showed, but also:
default void remove()
Removes from the underlying collection the last element returned by this iterator (optional operation).

Note this says that it is an "optional operation".

If the declared, compile-time type of your reference variable is Iterable, Collection, List...I am not going to repeat the whole enumeration of known possibilities from the Javadocs shown above, or any abstract or concrete class that implements them, you will be able to say:

i.remove(); // this will compile

Now comes the tricky part, or why this is a reasonably good question.

Just because it will compile, doesn't mean you are okay to use it!

Note the following legal code, which would inevitably lead to a RuntimeException, which if not caught (and classically we are trained not to catch these) would fatally crash the thread it was running in, also, you can note that we get a peek at the normally unseen name of the type of the Iterator you actually get back:
jshell> List<Integer> a = List.of(2, 4, 6, 8);
a ==> [2, 4, 6, 8]

jshell> Iterator<Integer> i = a.iterator();
i ==> java.util.ImmutableCollections$ListItr@41906a77

jshell> i.hasNext();
$3 ==> true

jshell> i.next();
$4 ==> 2

jshell> i.remove();
|  Exception java.lang.UnsupportedOperationException
|        at ImmutableCollections.uoe (ImmutableCollections.java:73)
|        at ImmutableCollections$ListItr.remove (ImmutableCollections.java:248)
|        at (#5:1)


Everyone keeps telling you to code to Interface, not Implementation.

Well, yeah, in the case of Iterable, Collection, and List, all of them expose .remove() as a legal method for your Iterator<T> that will compile if you call it.
But if the actual, runtime type of what you are using the interface to access is either Immutable, or even just fixed-size (as what is returned from Arrays.asList( myArray ); ), calling .remove() will kill your program (or at least your thread).  Yikes!!

I have written (too) much about this on another thread in Java-In-General.
My personal feeling is that a beginner-friendly language should not give you "Big Red Buttons" to push that will kill your program, which in this case means it is not great to have people calling methods on an interface, which compile just fine, but where some are guaranteed to crash at runtime.
We discussed (briefly) whether or not Java is still intended to be "Beginner-Friendly" (my contention is that it indeed is) and the difficulties involved in declaring a suitable number of distinct interface types to preclude this situation (it would be very difficult, with a resulting huge number of interfaces that would also confuse people and make maintenance difficult).

So I will go back to saying, as a General Rule, you should be coding to Interface, not Implementation.

But I have shown one of many cases, where to have code that runs correctly, you need to be aware of which calls are actually legal and supported based on the ACTUAL, RUN-TIME TYPE of the objects to which the references refer.  They are all over the place when using Java Collections Framework interfaces.

Note that you still don't need to know what the code looks like for each possible method call using such a reference.

But yeah, you do need to make sure for example that your List<T> is fully mutable, fixed-size, or immutable.

Just seeing List<T> doesn't answer that question in Java, you do need to be thinking about what it is actually referring to.
This particular issue is less prominent in some other languages, which have other Very Annoying Problems of their own, so I don't recommend switching languages as a solution.

Lastly, because I somewhat recently thought that Local Variable Type Inference might help me out of this "Sure, it will compile, but will fail at runtime, if I make various mistakes that seem easy to make" situation, some approaches that I had tried that don't buy you anything much in this regard.  I tried them because I am highly curious, and I know that you are Extremely Curious, so I will save you the trouble by showing the results here:

jshell> var b = List.of(1, 3, 5, 7, 9);
b ==> [1, 3, 5, 7, 9]

jshell> Iterator<Integer> iii = b.iterator();
iii ==> java.util.ImmutableCollections$ListItr@cac736f

jshell> iii.hasNext();
$8 ==> true

jshell> iii.next();
$9 ==> 1

jshell> i.remove();
|  Exception java.lang.UnsupportedOperationException
|        at ImmutableCollections.uoe (ImmutableCollections.java:73)
|        at ImmutableCollections$ListItr.remove (ImmutableCollections.java:248)
|        at (#10:1)

jshell> var iiiiii = b.iterator()
iiiiii ==> java.util.ImmutableCollections$ListItr@7d6f77cc

jshell> iiiiii.hasNext();
$12 ==> true

jshell> iiiiii.next();
$13 ==> 1

jshell> iiiiii.remove();
|  Exception java.lang.UnsupportedOperationException
|        at ImmutableCollections.uoe (ImmutableCollections.java:73)
|        at ImmutableCollections$ListItr.remove (ImmutableCollections.java:248)
|        at (#14:1)


Bottom line, "Code to the Interface, not the Implementation" is still great advice.
In specific areas in Java, you need to make sure you aren't telling your Pug to pull an 18-wheeler out of a ditch, or whatever analogy you prefer to restricting the calls you make on a reference variables to ones that are actually legal for the actual runtime type they are pointing to at that moment.
 
Nyeng Gyang
Ranch Hand
Posts: 113
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:... if you wanted you could print out its name. Like so:


In the foregoing line of code you provided, I guess you meant the following line of code, since it is the type/class of the returned iterator, rather than the type/class of the arraylist, that I am interested in knowing more about (recall that I already know the type/class of the reference identifier a):This line of code informs that the type/class of the returned iterator is java.util.ArrayList$Itr, which some Googling reveals is a nested class in class ArrayList that is named Itr.

Jesse Silverman wrote:Everyone keeps telling you to code to Interface, not Implementation.


Despite the utility of the foregoing remark you have made, once in a while, I nonetheless seek to peek into the inner workings of things, just for the sake of curiosity.  :-) For one, I imagined that that iterator was associated with class ArrayList and, in general, such an iterator would be associated with any collection that creates an interface Iterator<T> instance using the iterator() method.
 
Marshal
Posts: 73760
332
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Search your Java┬« installation folder for a file called src.zip, maybe in the lib directory. Unzip that and search in the java.base subdirectory for java, then util, then ArrayList.java. You will find the Iterator in that file; search for private class Itr. That should give you all the information you want.
 
Campbell Ritchie
Marshal
Posts: 73760
332
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jesse Silverman wrote:. . . Every class that implements Collection is guaranteed and required to provide a working implementation of:
Iterator<E> iterator()

From Java1.2, when the Collections Framework was introduced, until Java1.4, Collection had an iterator() method, which as Jesse says, returns an Iterator, whose details you can find from this Java7 API link. In Java5, the for‑each loop wass introduced, which can iterate an Iterable, or an array, and the iterator() method was moved from Collection to Iterable. Since Collection extends Iterable, the removed method wass replaced there by inheritance. If you omit any methods in any non‑abstract Collection, the code will fail to compile. So, as Jesse says, all those classes must have an iterator() method.

. . .
Iterator<Integer> i = a.iterator();

As Jesse says, that must return an instance of a concrete implementation of Iterator, and that will have all the methods specified in those interfaces.

. . . it is not required to know this, . . .

Agree. You don't need to know such things, but they can be interesting to know about. Different List implementations supply different Iterator implementations.I shall let you find out whether the code for those implementations is in src.zip.
 
Nyeng Gyang
Ranch Hand
Posts: 113
1
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Search your Java® installation folder for ....


The information about where those abstract methods are implemented suffices for me, thanks.
 
Campbell Ritchie
Marshal
Posts: 73760
332
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
 
Jesse Silverman
Bartender
Posts: 1059
33
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
For posterity, those reading the thread in the future will see what I have recently learned about the upper bounds limits of treating the idea of coding to interface as "look at the return type you get back" versus "fully read the JavaDocs to understand what you can rely on about what you just got back from your API call".  That is still "coding to interface" but more nuanced and requires a bit more attention than I was sometimes paying.

In other words, there is truly a good bit more to it than I had realized by a month ago if you want your code to be robust and trustworthy, as evidenced by all the posts I'd made saying "Okay, great, so I have a List<T>, whatever THAT means!"
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic