• 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

Wildcards in Generics

 
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Tobias Bachert posted a truly impressive code snippet in a discussion about how to achieve a kind of polymorphism where the signature alone is not enough to choose the method you need. His code made me realize I needed to learn more about generics, so I've been poring over them for the last few days. Most of the time, Cay Horstmann's excellent "Core Java" tells me the answers to my questions, but I was having a really hard time understanding what wildcards are for. Turning instead to "Head First Java," I read Sierra and Bates's take on generics, particularly their explanation as to why something like <T extends Animal> is necessary to polymorphism when passing what they call "generified" parameters. That all made pretty good sense. But, towards the end of their discussion, they introduce wildcards in a way that, to me, seemed to suggest they were duplicative of what the extends paradigm does.

Lo and behold, they actually then say this:

Sierra & Bates wrote:
This:

public <T extends Animal> void takeThing(ArrayList<T> list)

Does the same thing as this:

public void takeThing(ArrayList<? extends Animal> list)



That seemed like a pretty direct confirmation of what I was thinking. They go on to explain that the wildcard version is the one to use when you don't want to use "T" again. For example, they suggest not using wildcards in a case like this:

Because that gets you out of the somewhat clunkier alternative:

But I am thinking there's also the benefit of not being able to use T again. For example, consider this code:

Having access to "T" at Line 27 makes it possible for this code to sneak an Animal into an ArrayList that should only have Dog objects in it. This results in a ClassCastException at Line 13, when iterating over the ArrayList attempts to assign an Animal (that is not a Dog) to dog.

If I rewrite the offending routine with a wildcard, an attempt at explicitly downcasting the new Animal into a Dog is forbidden by the compiler:

Without the "T" type parameter, I can't cast the mismatched object to the type the compiler accepts for the ArrayList.

So here are my questions:

1. Are Sierra and Bates correct when they say public <T extends Animal> void takeThing(ArrayList<T> list) is the same as public void takeThing(ArrayList<? extends Animal> list), other than that there is no way to reference the non-existent type parameter?

2. Is the wildcard alternative the better choice when I want to avoid the risk of a type mis-match in a collection? (Alternatively, how does one know when to use which form, wildcard or named type parameter?)
 
Ranch Hand
Posts: 531
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Stevens,

What's the moral of the story?

When using generics, avoid brittleness..? It seems so. If generics are meant to cut down on the amount of casting and ease polymorphic operations on collections, why cast?

For the sake of argument:

public <T extends Animal> T doSomething(List<? extends T> values) {
       return (T) values.get(0);
   }

Then you can cast to T easily, but one shouldn't write one's code in a way where such a cast would be needed in the first place. Keep it simple.

Best for code re-use is to keep well-planned and well-designed functionality in jars.

With best regards,

Anton.
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stevens Miller wrote:Is the wildcard alternative the better choice...


In my experience, if it really is an "alternative", the answer is probably 'no'.

FYI, my rules of thumb:
1. Generics is an addition to the language, and actually works a bit like a pre-processor. For that reason, it's not a 100% solution, and for that reason, it's usually best to keep it "as simple as possible, but no simpler".
2. Avoid wildcards if you possibly can. Exception: T extends Comparable<? super T> (and similar constructs).

Your example is also quite a nightmare mixture of generics, static, and potential lambdas - the latter of which I'm not (yet) qualified to give advice on - so I suspect you're asking for trouble.

Point 1 above notwithstanding, I've generally found that when I run into problems with generics, it's almost always because I'm overthinking things (often because I'm trying to use generics for the sort of stuff that is really a runtime check); and there's often a much simpler solution available.

So perhaps you should get back to basics and ask yourself: What is the intent of all this?

HIH

Winston
 
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:
In my experience, if it really is an "alternative", the answer is probably 'no'.



Agreed. This seems to be more like two different features, that are related, and kinda accomplishes the same thing (within a limited context).

Henry
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic