• 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 all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Paul Clapham
  • Bear Bibeault
  • Jeanne Boyarsky
Sheriffs:
  • Ron McLeod
  • Tim Cooke
  • Devaka Cooray
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Jj Roberts
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • salvin francis
  • Scott Selikoff
  • fred rosenberger

Generic Question: wildcard with super

 
Ranch Hand
Posts: 124
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The following code is wrong at line 1.
Anybody knows how to modify the the line 1 to make it work? Thanks

List< ? super Number> l = new ArrayList<Number>();
l.add( 12 );
for(Number s: l) //#1
System.out.println( s);
 
Ranch Hand
Posts: 2410
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You could just take the wildcard out and make the parameter Number. Is there a reason you need a wildcard?
[ May 08, 2006: Message edited by: Keith Lynn ]
 
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Tiffny,

Try removing "? extends" and try again.

Steve
 
Tiffiny Yang
Ranch Hand
Posts: 124
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I know removing '? super' will work, I just want to know if I instantiate the way like that, how am I going to display the content of list.
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Tiffny,

I am not sure if I completely understand your question. Is this the answer that you are looking for?

for (Number n : l)
System.out.println(n);

Steve
 
Tiffiny Yang
Ranch Hand
Posts: 124
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, that's my question.

I'd like to use the following enhanced loop to display content, but the code won't pass compile.
I am interested in knowing how to modify the enhanced loop to display the content.

for (Number n : l)
System.out.println(n);


Thanks
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Tiffny,

The following code compiles and runs for me.

Steve

import java.util.*;

public class Test {

public static void main(String[] args) {
List<Number> l = new ArrayList<Number>();
l.add( 12 );
for(Number s: l) //#1
System.out.println( s);
}

}
 
Keith Lynn
Ranch Hand
Posts: 2410
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think if you leave the wildcard in, you will have to treat the contents of the list as Object and convert them to Number if you use them.
 
Author
Posts: 836
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have ammended this post because I was unclear in a few places.

The problem is occuring because of the return type of the get() method on a List where that list is declared to have a "? super" (lower bound) generics type. Think about what you're doing: you're saying that the list may potentially be any superclass of Number... so when retrieving that type, what type would you like returned exactly? We could have instead (for the sake of argument) a list List<? super Integer>... but then in fact we might have List<Number> or List<Object> - clearly when using "? super", the best we can do in Java is draw out an Object type, so get() will always return an Object when using a lower bound wildcard (this nomenclature helps to visual the inheritence hierarchy and what's going on in the compiler).

When using "? extends" (upper bound) you cannot invoke any setter methods (i.e. those which take the generic type as an argument), because you don't know how restrictive the actual list is. For example List<? extends Number> could in fact be List<Integer> - in which case you can't put a Double in there! You probably won't be able to put a Number either (even if Number was concrete and you could potentially create a new instance). However, with an upper bound wildcard "? extends X" you guarantee that the type will be X or a subclass, so any get() methods will return type X.

When using "? super X" (lower bound) you can invoke an add method provided the argument is of the type X or a subclass. For example, suppose we have List<? super Hashtable<Object,Object>> - we know that this List must be one of:

List<Object>
List<Dictionary>
List<Hashtable>

[I've omitted qualified names and other generic types for clarity]. So it will certainly be true that if we try to add a java.util.Properties (a subclass of Hashtable) object to the List that it will be a subclass of Object, Dictionary or Hashtable. However, we can't just add anything, because it is possible that our List is in fact List<Hashtable> rather than, say, List<Object> - and since List<Hashtable> is the most restrictive type allowed, this is also the bound placed on things added via add() - they must be Hashtables or subclasses.

Note that if you use the unbounded wildcard "?", you can extract things as Objects but can never add data to your collection - not even Objects, as the actual type could be much more restrictive; for example List<?> could in fact be List<String>, so we certainly can't add an Object.

Looking at your code, if you were only extracting numbers from your list, and knew they were Number instances, you could write "? extends" which will then cause List<? extends Number> to return a pre-cast Number instance from get(), or indeed from an Iterator:

But if you do this you will now find you cannot invoke the add() method, because now you're using "? extends" (upper bound), you can't add things in to the collection!

As others have commented it is best here if you use:This is valid because your list will indeed store all Numbers (in one subclass or another) and will return them cast as Numbers. You don't need the "? super" bit here, and (although open to much debate), this is only really useful when you don't know about the generic type your list will actually be declared to hold. It is unnecessary to use wildcards for method-local variables.
[ May 09, 2006: Message edited by: Charles Lyons ]
 
Ranch Hand
Posts: 286
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

this will be fine, its because the most super is an object so you must use anobject inthe for.
arno
 
Charles Lyons
Author
Posts: 836
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

this will be fine, its because the most super is an object so you must use anobject inthe for.
arno



You are correct - it works and it answers the question. But in general, the fact that you've lost knowing that your ArrayList contains Numbers (and you would then have to do that cast explicitly) still makes me believe that using:

List<Number> = new ArrayList<Number>();

is the cleanest thing here.
 
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
dear frnd!

ALways Remember that!!
U Should not use Wild Cards in DECLATION......Of variables
like List<? extends Number> = ArrayList<Number>;
bcoz generics dosenot allow polymorphism,,
so,

Whatever type u give here List<...> should be ArrayList<...>
no sub classes/ super classes
 
Ranch Hand
Posts: 324
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi ranchers

What my concept is that the above code will store values in form of super class object of Number i.e. Super class of Number is Object.
So what happens when l.add( 12 ); executes is
1 - Integer Object is created through AutoBoxing
2 - As Integer IS-A Object and our list can accept Object(super class of number)so this value is stored in List as Object.
At line # 1 ( for(Number s: l) ) we try to treat an object as number which causes error.

Guys please correct my if I am wrong

Thanks
 
Charles Lyons
Author
Posts: 836
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

As Integer IS-A Object and our list can accept Object(super class of number)so this value is stored in List as Object.


No! This the trap I nearly fell into with my post earlier... it is in fact quite confusing at first glance. Let me try to explain, although this may not sound crystal clear! If not, please let me know how to clarify.

What you need to grasp is the difference between a generic collection (or any other object) and a generic reference.

List<Number> means an object (in fact a List collection) which can hold Numbers or any subclasses. That's the easy bit!

List<? super Number> is a reference data type, meaning that the actual value held by such a variable should be a List<X> where X is a Number or a superclass of Number. List<? super Number> does not mean the list can contain any superclasses of Number. In fact, in general, this is not true, as we now show...

Let's take two examples:this is clearly valid because Object is a superclass of Number; so I go and invoke:and everything would in theory work okay (this won't happen, the compiler will complain and the next example shows why). But now I alter the declaration to:Again this is valid because Number is treated as a superclass of itself. But now I go to add an Object:Now what happens? The actual list type is ArrayList<Number>, so we can't add an Object to it! This will raise a compiler error.

So both examples raise a compiler error because you can't add a superclass of a class X to any (lower bound) generic type of the form "? super X" simply because the compiler doesn't know what type of list is actually on the left. The only guarantee we can make about List<? super Number> at compile time therefore (and due to type erasure this is the only place generics are really useful) is that the List will contain subclasses of Number - this is because a List<X> with X a superclass of Number implies that it may contain any elements which are Numbers or subclasses of it (think about an inheritence tree and this becomes 'obvious').

A key rule is: you can only create definite generic types - you cannot use wildcards when creating a new object (this makes little sense). You can only use wildcards to reference definite generic types.

You are correct about the autoboxing, but that gets converted to Integer directly, which is a subclass of Number and therefore can be added to the List<? super Number> type.

You are correct that "we try to treat an object as number which causes the error". But the explicit reason for the compilation error is because we have no upper bound on the generics type, it could potentially refer to a List<Object> (since Object is a superclass of Number). So the only guaranteed return type from the get method or from an Iterator is Object - the only common data type for all objects in the JVM.
[ May 09, 2006: Message edited by: Charles Lyons ]
 
Amirr Rafique
Ranch Hand
Posts: 324
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Charles
Please see below code, I have tried to summarised what I have understood from your revious post.

Please correct If I am wrong.

Thanks
 
Charles Lyons
Author
Posts: 836
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Please correct If I am wrong.


That seems correct to me... at least from the generics side of things. Interestingly you've chosen not to put any get() calls in there... if you did they would all return an (uncast) Object.

To make it clear, you could have placed this block:anywhere after an assignment of myList... it is irrelevant what actual declared generic type (on the right hand side of the assignment) the list is, this block will always behave in the same way given List<? super Number>.

Have you thought about the similar code using <? extends Number>. In that case you wouldn't be able to invoke any add() methods, but calling get() would return a (pre-cast) Number!
 
Because those who mind don't matter and those who matter don't mind - Seuss. Tiny ad:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
reply
    Bookmark Topic Watch Topic
  • New Topic