wood burning stoves 2.0*
The moose likes Beginning Java and the fly likes Java collection Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "Java collection" Watch "Java collection" New topic
Author

Java collection

David Spades
Ranch Hand

Joined: Feb 01, 2014
Posts: 194
after discussing about generics, I tried it for a bit to refresh my memory, and then I realized, apparently I haven't fully mastered this feature. there are several construct that I haven't seen before. I read Java tutorial docs in oracle about this subject, but I still have some blind spot.


so :
1. in this declaration, what should I put in the arraylist's bracket? any type that's a subclass or A or does it have to be A and only A? and what if it's a lower bound being used on the left hand side?
2. in this upper bound wildcard, I can't add any item to the collection, even when it's of type A. why is this? what scenario is this constraint trying to prevent?
3. if I use ? super A, then list can be populated only with item of type A or its subclasses (rather contradictive with the "super" bound). why is this?

Thanks
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7552
    
  18

David Spades wrote:1. in this declaration, what should I put in the arraylist's bracket? any type that's a subclass or A or does it have to be A and only A?

The first (A or a subclass).

2. in this upper bound wildcard, I can't add any item to the collection, even when it's of type A. why is this? what scenario is this constraint trying to prevent?

Simply put: misuse.

People often misunderstand what the "?" in "? extends" means: It does NOT mean "anything", it means "an unknown type", so the declaration:
List<? extends Fruit>
means "a List of an unknown type that extends (or is a) Fruit".

Therefore, the assignment could be:
List<? extends Fruit> fruits = new ArrayList<Fruit>();
or:
List<? extends Fruit> fruits = new ArrayList<Apple>();
or:
List<? extends Fruit> fruits = new ArrayList<Orange>();
but the minute you use the reference 'fruits', the compiler doesn't know the actual type of the List. Therefore it can't allow you add anything to it, because it doesn't know whether what you're adding (even if it's a Fruit) is the right type for the List.

3. if I use ? super A, then list can be populated only with item of type A or its subclasses (rather contradictive with the "super" bound). why is this?

Basically, for the same reason as above:
List<? super Orange>
means "a List of an unknown type that is a superclass of (or is an) Orange".

So any of the following assignments are fine:
List<? super Orange> fruits = new ArrayList<Orange>();
List<? super Orange> fruits = new ArrayList<Fruit>();
List<? super Orange> fruits = new ArrayList<Object>();
but this one isn't:
List<? super Orange> fruits = new ArrayList<SeedlessOrange>();

So even though the actual type of 'fruits' is not known, in this case the compiler DOES know that it must be one that can take an Orange or a subclass.

Hope it helps.

Winston

Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
David Spades
Ranch Hand

Joined: Feb 01, 2014
Posts: 194
1. so basically, the bracket on the right hand side can be filled with any type that satisfies the wildcard on the left hand side?
2. what are the effects on the type chosen for the right hand side? lets say A has 3 levels deeps of inheritance A->B->C->D, what effect does choosing B,C or D for the right hand side?
3. I thought when using upper bound, all the items extracted from the collection would automatically be cast to the upper bound type?
4. also, when using lower bound, items can be added with no problem, but the items added can only be subclasses (instead of superclass) of the lower bound (seems like counter intuitive)?
5. I tried the following:

Class hierarchy is A->B->C
my question is, when extracting the items out of listA, how does the compiler know what methods available for the extracted item? if it's upper bound, you can use the assumption that all items are cast as the upper bound, so only methods from the upper bound type will be available, but what about lower bound like this one?
thanks
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38042
    
  22
Yes. Remember that if you use <? extends Foo> you can take things out but not put things in.
Forget about casts. The compiler knows that everything which comes out of a Collection<? extends Foo> is a Foo, and that is enough to be getting on with.
Not sure about the upper bound question.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7552
    
  18

David Spades wrote:my question is, when extracting the items out of listA, how does the compiler know what methods available for the extracted item?

Beyond those defined for Object, it doesn't; although I suspect (TBH, I've never tried it, so I don't know for sure) that the compiler might allow you to cast the returned object to a C (on the assumption that anything added using its own add() method must be a C or a subclass), but it'll almost certainly give you a warning about unsafe casts and, after the assignment of 'a', any such cast could well result in a ClassCastException at runtime.

HIH

Winston
David Spades
Ranch Hand

Joined: Feb 01, 2014
Posts: 194
Campbell Ritchie wrote:Yes. Remember that if you use <? extends Foo> you can take things out but not put things in.
Forget about casts. The compiler knows that everything which comes out of a Collection<? extends Foo> is a Foo, and that is enough to be getting on with.
Not sure about the upper bound question.


that's yes for which question? number 1?

@Winston:
I tried it and it didn't give any warning or compile error. It however, gave me a runtime error.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7552
    
  18

David Spades wrote:I tried it and it didn't give any warning or compile error. It however, gave me a runtime error.

Sure it did, because you added an A, and you can't cast an A to a C.

I have to admit being quite surprised that it doesn't give you a warning though.

Winston
David Spades
Ranch Hand

Joined: Feb 01, 2014
Posts: 194
Yep,



simple casting is enough to access all methods available in class C and we know that the item was actually A. test() is just a blank public method I create in C only.
no warning, let alone compile error. but, I did get a big fat runtime error, as expected.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38042
    
  22
David Spades wrote: . . . that's yes for which question? number 1? . . .
Yes. No 1.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7552
    
  18

David Spades wrote:no warning, let alone compile error. but, I did get a big fat runtime error, as expected.

Fair enough. One thing that's worth remembering: Java generics isn't a universal solution, more like an 80% one; and the way it was implemented is actually a bit of a kludge (probably for backwards bytecode compatibility but, TBH, I'm not sure).

The fact is that you're unlikely to need a definition that includes wildcards in real life; they tend to occur far more often in parameters than on the LHS of assignments. And generics is good enough that if you run into problems, it's usually because you're over-complicating things.

HIH

Winston
David Spades
Ranch Hand

Joined: Feb 01, 2014
Posts: 194
let me summarize the discussion so far:
we shall refer the bracket content on the left hand side as "left expression" (because it may come in the form of expression ? extends A, etc) and the one on the right as "right type" (because it's always type on the right hand side)

1. It doesn't matter what type you choose for "right type" as long as when the wildcard on the "left expression" is substituted with "right type", the expression will pass, then it's all good
2. It has no effect whatsoever which "right type" you choose, there's not gonna be any effect at all. Is this true?

Thanks
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7552
    
  18

David Spades wrote:1. It doesn't matter what type you choose for "right type" as long as when the wildcard on the "left expression" is substituted with "right type", the expression will pass, then it's all good

I think so, but I'd say that:
"if a generic type expression on the left hand of an assignment contains a "?", then any type supplied on the right (which CANNOT contain a "?") must satisfy it".
is a bit clearer.
However, it doesn't cover the case where the right hand side of the assignment is an object (and therefore may not have a visible type), as in your 'listA = a' assignment.

In that case, the object's declared type (if specific) must be compatible with the lhs, OR it must have been declared with the same wildcard expression.

2. It has no effect whatsoever which "right type" you choose, there's not gonna be any effect at all. Is this true?

Not quite sure what you mean here, because we've already stated that the type on the right MUST be compatible with the expression on the left.

Personally, I dislike the term "wildcard" for "?" expressions (although I'm not quite sure what I'd use instead), because it makes people think that the type is somehow 'variable'. It isn't. At some point in the process, you must have supplied a specific type, and THAT is the actual type of the object. The "?" simply says that the compiler doesn't know what it is.

HIH

Winston
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Java collection
 
Similar Threads
Generic Question: wildcard with super
I have doubt in a question in Generics(Q16) SCJP5 K&B book
help with generics
Parameterized collections types holding subtypes aka generic polymorphism - how does it work?
Generic Problem