This week's book giveaways are in the Refactoring and Agile forums.
We're giving away four copies each of Re-engineering Legacy Software and Docker in Action and have the authors on-line!
See this thread and this one for details.
Win a copy of Re-engineering Legacy Software this week in the Refactoring forum
or Docker in Action in the Agile forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Generics doubt

 
Harvinder Thakur
Ranch Hand
Posts: 231
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


Can anybody tell me when is the actual type of <T> determined by the compiler for the method meth()?
If it is at LINE#1 then as per my understanding the cast at LINE#2 in method meth() from Float to Byte should fail as Byte IS-NOT-A Float because the cast to type (T) would already have been resolved at compile time and thus this should generate a compile time error?
But the code compiles and happily prints the output.
What am i missing here?
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're assuming that there's runtime type checking of the contents of the list itself, but that's simply not true. Generics work by erasure, which means (in essence) that the compiler enforces certain type restrictions, but at runtime, the types have been erased; the List itself works only with Object references. You're tricking the compiler by using that type wildcard. If you tried to take that Float out of the list from within main, the compiler will have inserted a cast to String, and you'd get a runtime exception at that point.
 
Rob Spoor
Sheriff
Pie
Posts: 20495
54
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
With method-local generics, the method call determines the actual type. For instance, Collections.emptySet() returns a Set<String> if the reference type the value is assigned to is Set<String>. In your example, it is LINE#1 that determines that T is Byte.

As EFH said, during runtime there is no more T so the cast is basically (Object). Because your example can cause problems the compiler warns you - casting to T is highly discouraged, and your example shows exactly why. That's a ClassCastException waiting to happen once you retrieve the Float object but assign it to a Byte reference.
 
Harvinder Thakur
Ranch Hand
Posts: 231
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry guys for posting a bit late. I was on a vacation
Thanks for your answers. i have a doubt.

Originally posted by Ernest-Friedman Hill:

If you tried to take that Float out of the list from within main, the compiler will have inserted a cast to String, and you'd get a runtime exception at that point.


The cast would not be a String but to a Byte as the list1 is a List of Bytes. Isn't it?

Suppose if i change the invocation on LINE#1 as
new Test().meth(list);// LINE#1
then what would be the generic type T resolved to? Is it Object ? I guess not because it is only Number which satisfies the construct <T extends Number> so it should be Number
 
Ankit Garg
Sheriff
Posts: 9509
22
Android Google Web Toolkit Hibernate IntelliJ IDE Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Taking the original code as base let me explain it to you.

Harvinder since the type of meth T is not used in the method except for the return type, so there are two ways that the type of T can be decided by the compiler.

1. By examining the type in which the return value is being catched. So if you write this

List<Byte> = new Test().meth(null);

then the compiler will know that the type of T is Byte. The other way is to use this syntax

new Test().<Byte>meth(null);

Now here too the compiler will be able find that the type of T is Byte.

But if you don't provide any information to the method, then the type of T will become Number as the declaration of meth defines <T extends Number>...
 
Harvinder Thakur
Ranch Hand
Posts: 231
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
o.k. that implies if I change <T extends Number> to <T> then the generic Type T would be resolved to an Object.
Moreover, the argument to meth(List<?> type) can accept a List of objects of any type. This makes it inappropriate to use in combination with generic type declaration of <T extends Number> as adding anything to a collection of generic type T declared within the method meth() can result in type unsafe addition as LINE#1 in original code shows.
Thanks guys for chipping in.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic