Meaningless Drivel is fun!*
The moose likes Java in General and the fly likes Generics Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Generics "is not applicable for the arguments"" Watch "Generics "is not applicable for the arguments"" New topic
Author

Generics "is not applicable for the arguments"

Michael Remijan
Author
Ranch Hand

Joined: May 29, 2002
Posts: 123
    
    5

I am starting to get into the world of generics. My first attempts have not been very successful. Here is some simple code I'm tying to compile:

public static final void main (String [] args)
{
class Shape {
}
class Box extends Shape {
}

LinkedList<? extends Shape> list = new LinkedList<Shape>();
list.add(new Box());
}
I'm using Eclipse 3.1 and the problem I'm getting is:

"The method add(capture-of ? extends Shape) in the type
LinkedList<capture-of ? extends Shape> is not applicable
for the arguments (Box)"

Because Box extends Shape I figured this should pass the bounding checks but I still don't know why I'm getting this problem. Help would be appreciated.


Java EE Evangelist — Author, EJB 3 in Action 2nd Edition — Java Community Process Member
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Imagine you also have a Shape subclass Circle, then the following would be legal, too:

LinkedList<? extends Shape> list = new LinkedList<Circle>();

Should the compiler allow you to add Box instances to that List?


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Michael Remijan
Author
Ranch Hand

Joined: May 29, 2002
Posts: 123
    
    5

That's exactly the point. I want to put Shapes in the list whether they be Box, Circle, or Elipse. I know this has got to be a common request. Think of Swing action listeners....many different implementing classes but I'm assuming it should be possible to put them all in the same list if it's something like LinkedList < ActionListener >


Originally posted by Ilja Preuss:
Imagine you also have a Shape subclass Circle, then the following would be legal, too:

LinkedList<? extends Shape> list = new LinkedList<Circle>();

Should the compiler allow you to add Box instances to that List?
Rick O'Shay
Ranch Hand

Joined: Sep 19, 2004
Posts: 531
This meets your objective because Box and Circle and what have you are all Shapes. A Circle IS-A Shape so no gymnastics are required to fill this list with Circles or Boxes or what have you.

List<Shape> list = new LinkedList<Shape>();
list.add(new Box());

The code you had, which follows, did not work for reasons are not immediately obvious or simple to explain. The bottom line is wildcards are used to define generic classes and methods, not as concrete references.

LinkedList<? extends Shape> list = new LinkedList<Shape>();
list.add(new Box());

That would work if list.get(...) was called but you cannot assign a concrete to a wildcard reference and then call a method accepting a generic method argument. I'll defer to Angelika Langer for an accurate explanation of why but in general just use wildcards (bounded or unbounded) when defining generic methods and classes:

http://www.langer.camelot.de/GenericsFAQ/JavaGenericsFAQ.html

[ August 11, 2005: Message edited by: Rick O'Shay ]
[ August 11, 2005: Message edited by: Rick O'Shay ]
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Rick, I guess when you say "this", you mean the code that *follows*? Took me a while to get it... :roll:
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Michael Remijan:
That's exactly the point. I want to put Shapes in the list whether they be Box, Circle, or Elipse.


Well, yes, but with

LinkedList<? extends Shape>

you are saying that it could be a linked list that can only hold specific shapes. If you want a list that always can hold all kind of shapes, just use

LinkedList<Shape>

as Rick already indicated.

Does that help?
Rick O'Shay
Ranch Hand

Joined: Sep 19, 2004
Posts: 531
I removed the ambiguity to "this will not work". What's tricky about this question is that you can declare references that accept wildcards but then there are restrictions on what you can do with it, specifically calling other generic methods through it. That's why a good policy is to only use them to write your own generic methods and classes. Plus, it doesn't buy you anything to say "I want this class to be at least Shape" because "Shape" already does that. It does make sense to say "I want this collection to be generic but the specific type must be greater than or equal to Shape (extends) or less than a Hexagon (super).
Michael Remijan
Author
Ranch Hand

Joined: May 29, 2002
Posts: 123
    
    5

Well here is the code that works.


I still do not understand why LinkedList<? extends Shape> does not work because this is suppose to hold a list of "an unknown type that is a subtype of T" This is directly out of the generics tutorial. Since a Box is a subtype of Shape I'm thinking it should work.
David Weitzman
Ranch Hand

Joined: Jul 27, 2001
Posts: 1365
A collection with a wildcard type parameter is, in a sense, readable but not writable. That's not entirely accurate because you can remove objects from such a Collection, but you can't stick new objects in. Thus if you're writing a method that, say, adds the values in a list, it would be best to use a wildcard bounded signature:



I can call sum(Arrays.asList(new Float[]{1f, 2f, 3f})) and this will work fine. If the signature just said Collection<Number> the method call wouldn't compile!

But if you're writing a method that increases all the numbers in a list by some amount, you need a signature that lets you put the incremented values back into the Collection:


[ August 11, 2005: Message edited by: David Weitzman ]
Rick O'Shay
Ranch Hand

Joined: Sep 19, 2004
Posts: 531
>> I still don't understand why LinkedList<? extends Shape> doesn't work.

Answer: it does work, problem solved.

This is what fails:

list.add(new Box());

The reason is that you have a reference to an unknown specific type. The compiler will not allow you to call a generic method (add takes the type) because it doesn't know what type it should allow for that reference, it doesn't look to see what the list contains because there is no list: it's compiling not executing. You can call size() or get(), however, since they don't have generic parameters.

This is definitely going to be a point of confusion going forward but resolve it like this: use wildcard when writing generic classes or generic methods; don't use them as concrete reference. So, if you want a generic method that accepts a T but you want to range bind the parameter then use bounded wildcards:

<? extends Shape> or <? super Hexagon>

Side note: extends includes the upperbound while super is non-inclusive, Hexagon would not be acceptible for example.

I can see generics is going to be a blast for the SCJP writers. Glad I took my test early! It still had plenty of generics, maybe even some wild card questions, but then I can't say.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Michael Remijan:

I still do not understand why LinkedList<? extends Shape> does not work because this is suppose to hold a list of "an unknown type that is a subtype of T"


Did you take a look at my example? Why should the compiler allow you to add a box to a list that is supposed to hold circles?
[ August 11, 2005: Message edited by: Ilja Preuss ]
Rick O'Shay
Ranch Hand

Joined: Sep 19, 2004
Posts: 531
Even if Circle was replaced with Box it would not work. Allowing a reference declaration with a bounded wild card is for use in a generic class or method not as means of declaring a reference to use with a instance of that class or method. Again, the test is this: are you writing a generic class or method or using one? If it's the latter than do not use wild cards even if it let's you declare such a reference; that's not the purpose.

Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Rick O'Shay:
Even if Circle was replaced with Box it would not work. Allowing a reference declaration with a bounded wild card is for use in a generic class or method not as means of declaring a reference to use with a instance of that class or method. Again, the test is this: are you writing a generic class or method or using one? If it's the latter than do not use wild cards even if it let's you declare such a reference; that's not the purpose.


I disagree. Take this method for example:



If I understand correctly, this method cannot be called with a List<Box>, although a Box is a Shape. Declaring list as List<? extends Shape> would fix this problem.
Sachin Ahuja
Greenhorn

Joined: Aug 12, 2005
Posts: 13
The Wildcard instantiation using lower bounds is very different from the same using upper bounds - but the functionality is VERY VERY LOGICAL.

I have written down a rationale of the same you can find a link to it here:
http://www.sachinahuja.com/TigerNotesIndex.html


(sorry about posting this reply as a new thread also)
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Sachin: I deleted the other thread for you, since you subsequently put the post here in its preferred location.


"I'm not back." - Bill Harding, Twister
 
 
subject: Generics "is not applicable for the arguments"