aspose file tools*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes Regarding generics, mixed with legacy collection code. Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "Regarding generics, mixed with legacy collection code." Watch "Regarding generics, mixed with legacy collection code." New topic
Author

Regarding generics, mixed with legacy collection code.

Andreas Svenkson
Ranch Hand

Joined: Jan 17, 2011
Posts: 179

Consider the following...



Now... imagine this was an exam question... Options could be:

1: Code compiles and runs, printing first the Integer then the String inside the list.
2: The code compiles but throws a runtime exception.
3: The code fails to compile.

Right... this is purely my own creation, inspired from a textbook question. The problem for me here, is that if you run this code, there will be a ClassCastException thrown at runtime. The underlying question is, why does this happen when the enhanced for loop is expecting (casting) the instances in the list to Object and not Integer?

At first I thought it was because 1: the list is created as an <Integer> generic type, meaning that the compiler automatically inserts casts to Integer whenever we try to extract something from it. This together with 2: the enhanced for loop really uses the Interator mechanic, and since the generic type of the list is <Integer>, then so is the Iterator (working behind the scenes of the enhanced for loop). Meaning there is an invisible cast to Integer by the invisible Iterator, behind the for loop.

BUT (and here's what really confuses me), if we remove the for loop, and uncomment the Iterator lines above it, the code runs fine! (compiles with warnings due to the add() method, but it runs perfectly and prints the objects). Even though the Iterator is defined as having generic type <Integer> !

The 2 questions this boils down to are...

1: Why does the enhanced for loop cause an exception, even though we're casting the objects to Object?
2: Why does the Iterator NOT throw an exception, even though it is defined as generic type <Integer>? I think this should imply a behind the scenes casting to Integer, but obviously it doesn't?

// Andreas


Ikpefua Jacob-Obinyan
Ranch Hand

Joined: Aug 31, 2010
Posts: 394

Andreas Svenkson wrote:
Consider the following...



Now... imagine this was an exam question... Options could be:

1: Code compiles and runs, printing first the Integer then the String inside the list.
2: The code compiles but throws a runtime exception.
3: The code fails to compile.

Right... this is purely my own creation, inspired from a textbook question. The problem for me here, is that if you run this code, there will be a ClassCastException thrown at runtime. The underlying question is, why does this happen when the enhanced for loop is expecting (casting) the instances in the list to Object and not Integer?

At first I thought it was because 1: the list is created as an <Integer> generic type, meaning that the compiler automatically inserts casts to Integer whenever we try to extract something from it. This together with 2: the enhanced for loop really uses the Interator mechanic, and since the generic type of the list is <Integer>, then so is the Iterator (working behind the scenes of the enhanced for loop). Meaning there is an invisible cast to Integer by the invisible Iterator, behind the for loop.

BUT (and here's what really confuses me), if we remove the for loop, and uncomment the Iterator lines above it, the code runs fine! (compiles with warnings due to the add() method, but it runs perfectly and prints the objects). Even though the Iterator is defined as having generic type <Integer> !

The 2 questions this boils down to are...

1: Why does the enhanced for loop cause an exception, even though we're casting the objects to Object?
2: Why does the Iterator NOT throw an exception, even though it is defined as generic type <Integer>? I think this should imply a behind the scenes casting to Integer, but obviously it doesn't?

// Andreas



Andreas wrote: The problem for me here, is that if you run this code, there will be a ClassCastException thrown at runtime.


Jack wrote: Hello Andreas, I have just passed this code to my eclipse, it compiled an ran perfectly!... In three ways, independently and together, the code compiled and ran perfectly. I guess I still dont have a perfect understanding of mixing legacy and non-legacy ,
I will appreciate it if someone can help, because at this point I am a little confused


OCPJP 6.
In Your Pursuit Towards Certification, NEVER Give Up.
Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3378
    
    9
It looks as if the enhanced for statement casts the references internally, before it assigns them to the variable. I'm not certain though.
Ikpefua Jacob-Obinyan
Ranch Hand

Joined: Aug 31, 2010
Posts: 394

Stephan van Hulst wrote:It looks as if the enhanced for statement casts the references internally, before it assigns them to the variable. I'm not certain though.


Jack wrote:Hello Stephan, your thought is as good as mine, however runtime exception is thrown when you attempt to loop through the collection with a specific type, example if you change the 'Object o' inside the for loop to 'int i', my thinking is that both the iterator and the for loop have similar 'modus-operandi' in terms of getting out the elements from the collection.
Andreas Svenkson
Ranch Hand

Joined: Jan 17, 2011
Posts: 179
Stephan van Hulst wrote:It looks as if the enhanced for statement casts the references internally, before it assigns them to the variable. I'm not certain though.


Yes indeed that was my thinking too but I thought that the enhanced for-loop in actuality uses an Iterator in the background, so it doesn't explain why using an Iterator doesn't cause the same exception.

Ikpefua I have no idea how it can work for you, have you tried compiling and running it from the command line, outside of eclipse? Personally I still use NetBeans, the transition to Eclipse will have to wait a bit ;)

EDIT: Whether or not the enhanced for loop uses an Iterator in the background aside, it also really bothers me that we can use an Iterator explicitly with a specified generic type of Integer and not get an exception at runtime when we hit the String.

// Andreas
Matthew Brown
Bartender

Joined: Apr 06, 2010
Posts: 4240
    
    7

Andreas Svenkson wrote:EDIT: Whether or not the enhanced for loop uses an Iterator in the background aside, it also really bothers me that we can use an Iterator explicitly with a specified generic type of Integer and not get an exception at runtime when we hit the String.

That's because of type erasure - the generic information simply doesn't exist at runtime. Which is why it's important to avoid mixing generic and non-generic code if at all possible.
Ikpefua Jacob-Obinyan
Ranch Hand

Joined: Aug 31, 2010
Posts: 394

Andreas Svenkson wrote:
Stephan van Hulst wrote:It looks as if the enhanced for statement casts the references internally, before it assigns them to the variable. I'm not certain though.


Yes indeed that was my thinking too but I thought that the enhanced for-loop in actuality uses an Iterator in the background, so it doesn't explain why using an Iterator doesn't cause the same exception.

Ikpefua I have no idea how it can work for you, have you tried compiling and running it from the command line, outside of eclipse? Personally I still use NetBeans, the transition to Eclipse will have to wait a bit ;)

EDIT: Whether or not the enhanced for loop uses an Iterator in the background aside, it also really bothers me that we can use an Iterator explicitly with a specified generic type of Integer and not get an exception at runtime when we hit the String.

// Andreas


Andreas wrote: it also really bothers me that we can use an Iterator explicitly with a specified generic type of Integer and not get an exception at runtime when we hit the String.

Jack wrote:Andreas, it bothers me too, I had to cancel an appointment (willingly) to study this problem, the definition of an iterator(according to the K & B Book Chapter 7, page 580) says "An Iterator is an OBJECT that is associated with a specific collection" that brings us back again to what we initially said, since an Iterator is an 'OBJECT' and 'Object o' inside the for loop is an 'OBJECT' they have a similar 'Modus-Operandi' 'behind-the-scenes', INDEPENDENTLY of the declared generic type <Integer>. Its like both loops are saying: "cast ANYTHING you bring out from the collection to Object".
And one more thing I just remember about the concept of 'Generic-Types'; "At Runtime The JVM Sees The Iterator Like This:"
and NOT like this:

Remember that looping is a runtime event.
I hope this theory is correct, otherwise I guess we need some help here. ...@Andreas...@Stephan, please tell me what you think.
Matthew Brown
Bartender

Joined: Apr 06, 2010
Posts: 4240
    
    7

OK, I've done a bit of experimenting with different versions and looking at the byte code (javap -c, for those that are interested). My conclusion is that this:
Produces identical byte code to this:
So that's what the compiler is doing with the enhanced for loop - and you can quite clearly see where the failing cast occurs,
Seetharaman Venkatasamy
Ranch Hand

Joined: Jan 28, 2008
Posts: 5575

Matthew Brown wrote:OK, I've done a bit of experimenting with different versions and looking at the byte code (javap -c, for those that are interested). My conclusion is that this:
Produces identical byte code to this:
So that's what the compiler is doing with the enhanced for loop - and you can quite clearly see where the failing cast occurs,


Not really! Compiler simply replace enchanced for loop by traditional for loop.so compiler convert the mentioned enchanced for as below.

so below code runs fine! though you can mix geniric with non-generic for backward compability, as matthew mentioned above avoid the mix/mess!

Andreas Svenkson
Ranch Hand

Joined: Jan 17, 2011
Posts: 179
Matthew Brown wrote:
Andreas Svenkson wrote:EDIT: Whether or not the enhanced for loop uses an Iterator in the background aside, it also really bothers me that we can use an Iterator explicitly with a specified generic type of Integer and not get an exception at runtime when we hit the String.

That's because of type erasure - the generic information simply doesn't exist at runtime. Which is why it's important to avoid mixing generic and non-generic code if at all possible.


Well that's possibly the explanation. However I was under the impression that the compiler is supposed to handle generic collections by automatically inserting casts when we retrieve something from such a collection. But perhaps that's only the case if we had an explicit variable assignment, as such:



But I still think it would make more sense to have an invisible cast whenever the Iterator.next() method is invoked.

// Andreas
Andreas Svenkson
Ranch Hand

Joined: Jan 17, 2011
Posts: 179
Matthew Brown wrote:OK, I've done a bit of experimenting with different versions and looking at the byte code (javap -c, for those that are interested). My conclusion is that this:
Produces identical byte code to this:
So that's what the compiler is doing with the enhanced for loop - and you can quite clearly see where the failing cast occurs,


Interesting! I should have read all responses before posting

And assuming this is right, then would you agree that the invisible cast inserted by the compiler is ONLY inserted when you actually assign the it.next() value to a variable ? It certainly would seem that way to me since it doesn't appear to be inserted if we just send the value of Iterator.next() to S.O.P.

// Andreas
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Regarding generics, mixed with legacy collection code.
 
Similar Threads
Enhanced for loop
ArrayList with Iterator new*
Using for..each loop on Object[]
Did the For loop lie
How do iterate 2 list's using for-each loop(enhanced for loop)