• 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
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Generics, multiple bounding types and efficiency

 
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

I read in Core Java: Vol 1 that if you have multiple bounding types for a type parameter, it is less efficient if you were to place a tagging interface as a bound at the head of the list. i.e. if this: <T extends Serializable & Comparable> would be less efficient than this: <T extends Comparable & Serializable>. The reason given is that the JVM during type erasure would replace the type parameter with Serializable everywhere it appeared and would therefor need to cast to Comparable when necessary. This is apparantly less efficient than the reverse.

Could anybody tell me why that is please? Why is it less efficient to cast to an interface with methods as opposed to a tag interface.


Thanks,
Alistair
 
Ranch Hand
Posts: 525
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I don't understand the question. Generic stuff doesn't make it into the executable code
so how can anything about generics affect run-time efficiency? If you're talking about
efficiency of the compiling process - then maybe. Please elaborate.

Jim...
 
Alistair Parler
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Jim,

Probably my fault.

Generic stuff -does- make it into executable code in this way:

First, define a generic class with a bounded type parameter:



This will be translated into a raw type which, after type erasure, corresponds to this:

Note that the type parameter has been replaced with *the first bounding type* - Comparable. Where the class is used in a "serializable" context and not in a "comparable" context, the bytecode must include casts. It necessarily needs to do this since we've made a compile-time promise that the type parameter is also a Serializable.

Now, if I had exactly the same generic class, but changed the bounding parameter order like this (i.e, changed the order of Comparable and Serializable):



then the resultant raw type would look different and become this:



Therefore the bytecode would now include casts to Comparable instead of Serializable (again, depending upon the context and the type inference at that point).

After these examples, my question really is: why is the first raw type more efficient than the second raw type? Why should I put the tag interface last? Why is casting to an interface which houses methods any more 'heavyweight' than casting to Serializable? All these are equivalent for this example so any answer will do.

Hope that clarifies things!

Any help greatly appreciated!


Thanks,
Alistair
 
Jim Hoglund
Ranch Hand
Posts: 525
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Alistair, I'm still quite confused. Where is 'T' in all of this? It seems that 'T',
rather than Comparable or Serializable, should show up in the concrete class.
Also, since Serializable is an empty marker interface with no methods at all,
I can't see it being used as either a parameter or return type. It has nothing
to offer a calling object, not even a constant.

Jim...
 
Sheriff
Posts: 22781
131
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
An example of how the JVM will execute this.

Java code:
When I disassemble Test1 and Test2 using "java -c" I get the following:
Both include the same instructions, only in different order. Note that checkcast will do the actual checking. If I would leave out the call to Test.doIt() then class Test2 still has the checkcast whereas class Test1 does not. So yes, it does lead to a little more speed if you minimize the number of casts by using the most often used type as the first one.

That said, that is really nano optimization. The speed increase is so minimal I can't even call it micro optimization. Even stranger, a little test I've done shows that the code with the check is faster:
Output:
18072362
16765182

On average, each call is less than 20 nanoseconds for both calls. The difference is less than 3 nanoseconds. I wouldn't bother changing anything for these differences.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic