• 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
  • Tim Cooke
  • Ron McLeod
  • paul wheaton
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
  • Himai Minh
Bartenders:

Diamond operator and wildcards

 
Ranch Hand
Posts: 185
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What happens when doing

?

It compiles and runs fine but what kind of ArrayList is actually created?

I don't understand why adding this gives a compilation error:

Thanks,

John
 
Bartender
Posts: 4568
9
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Exactly what type of ArrayList is created isn't all that important in that case. At runtime the type is erased anyway, so all that really matters is that something is created that's consistent with List<? extends Number>. The Java Language Specification may say something concrete.

But what matters in terms of your following line is the reference type. When the compiler type-checks that it doesn't try and work out the exact object that list is referencing. It just goes on the reference type. And that says it could be a List<Number>, a List<Integer>, a List<Float>, etc. And some of those can't be safely assigned to a List<Number>, so the compiler gives an error.
 
John Stark
Ranch Hand
Posts: 185
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hm, I see. I cannot add anything to the list as it is created with the 'extends' keyword. Is there anything I can do with the reference created in


?

 
Sheriff
Posts: 22857
132
Eclipse IDE Spring Chrome Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Not really. You could try to get Numbers from them, but the List is empty and cannot be filled without resorting to trickery (like casting to a raw List, then casting to any generic List).
 
Marshal
Posts: 80781
489
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Usually you get things out of a List<? extends Anything> but you can't put them in.You would need a list of something definite to put things into.
 
John Stark
Ranch Hand
Posts: 185
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Many thanks for the helpful replies. It makes much more sense now.

John
 
Campbell Ritchie
Marshal
Posts: 80781
489
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You're welcome
 
Ranch Hand
Posts: 411
5
IntelliJ IDE Java Linux
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When working with wildcards in generics, if you use <? extends Type> you cannot invoke methods that can mutate the structure, you can only invoke accessor methods to retrieve information from that structure. If you would like to call setter methods on a structure using wildcards you will have to use <? super Type>. On contrast if you use <? super Type> you cannot call accessor methods on that structure, this is known as the Get and Put principle.

So to make things a bit simpler just remember these 3 rules:

1. Use an extends wildcard (<? extends Type>) when you only get values out of a structure.

2. Use a super wildcard (<? super Type>) when you only put values into a structure.

3. Don’t use a wildcard when you want to both get values out and put values into a structure.

So from the code you provided seeing that list2 was declared as List<Number> which allows the list2 reference to get and put values, you cannot provide an alias for list using list2 since you declared list as List<? extends Number>.
 
Rob Spoor
Sheriff
Posts: 22857
132
Eclipse IDE Spring Chrome Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One addition to the above: if you use ? extends Type, null is a valid value for any mutator method. For instance, in a Collection<? extends Number>, I can add null (but nothing else). The reasoning is that, no matter what the actual type is, null can safely be cast to the type.
 
Rico Felix
Ranch Hand
Posts: 411
5
IntelliJ IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Another addition: if you use ? super Type, you cannot get a value out from the structure except an Object. For instance, in a Collection<? super Number>, I can get an Object (but nothing else). The reasoning is that, no matter what the actual type is, Object is the supertype of every reference type.

Example: The following is illegal



But the following is legal

 
Ranch Hand
Posts: 88
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Little more light on this.
Typically the <? extends Type> and <? super Type> was created in Java to allow the client code to iterate or modify the collection respectively.

1) Basically one would use <? extends Type> when one wants to pass a generic SubType List as a method argument for clients to iterate a collection

Say you have an Animal super class and Cat and Dog sub classes. Suppose you are doing some manipulation with one of either dogs or cats. You would want to
pass a List<Dog> or List<Cat> as a method argument to the method loopThroughAnimals

To do this in a polymorphic way i.e. to pass either List<Dog> or List<Cat> to the <code>loopThroughAnimals</Code> method you need to have the method signature as

By "Extends" syntax, you are telling your client that, I will accept any Type that "extends" Animals and allow you to ONLY read through the collection.

2) For "super", Say you are adding a series of dogs in your code and want to pass that collection to clients for modification. You don't want your clients to add a
cat into your collection by mistake. In this case,

The method signature needs to be

By this you are telling the client that, "I will allow you to add anything that's above the "Dog" in the hierarchy. Not anything below such as a Cat, as this may pollute your
collection.



 
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Sunderam Goplalan wrote:By this you are telling the client that, "I will allow you to add anything that's above the "Dog" in the hierarchy. Not anything below such as a Cat, as this may pollute your collection.


It would be really strange if you would have a class Cat that extends class Dog. If you do that, you're saying that a Cat is a special kind of Dog. My cat will certainly disagree with that... So, the second half of your example is a little strange.

The important point to remember about the List<? extends Animal> syntax is this: it means it is a List of some specific but unknown type that is a subtype of Animal (or type Animal itself).

Note that this does not mean: a List of objects of any arbitrary type that is a subtype of Animal (maybe even instances of different types that are subtypes of Animal).

There's a subtle but important difference here! All the elements of the list must be objects of a specific type, but you don't know what that type is.

This explains why you cannot add anything to a List<? extends Animal>, it is because the compiler does not know what the "?" stands for - it does not know what the actual specific type of the objects in the list is supposed to be. It won't allow you to add anything to the list, because it can't check that you're not adding anything that doesn't belong in the list. Example:

Note that the lists cats and dogs are both of type: List<? extends Animal>. We can see that for cats, the "?" actually stands for Cat, and for dogs, the "?" stands for Dog. However, you don't know this if you only look at the types of the variables cats and dogs. The compiler only looks at the types of the variable to determine what you can do with the variable, and from just that it doesn't know what the actual type of the elements of the list is.
 
Sunderam Goplalan
Ranch Hand
Posts: 88
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

It would be really strange if you would have a class Cat that extends class Dog. If you do that, you're saying that a Cat is a special kind of Dog. My cat will certainly disagree with that... So, the second half of your example is a little strange



I think I needed to clarify the above, what precisely I meant. I'm not saying that Cat extends Dog! I meant, Given the below, as an example



About the <? super Animal> use case, I meant that, say, a "collection


is already pre-filled with DOG instances". Suppose that another method "addMoreAnimals" that gets this collection as a parameter has the "potential" to add any subtype of Animal, by mistake, to the pre filled DOG collection. If one wants to maintain the sanity of the above collection and YET ALLOW that another "addMoreAnimals" method to ONLY
add Dogs in a guaranteed way, then that method's signature needs to be



The reason is that if you just had "addMoreAnimals(List<Animal>...), then this signature will allow the method to add ALSO Cat instances. Does that make sense?



 
Ranch Hand
Posts: 71
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rico Felix wrote:Don’t use a wildcard when you want to both get values out and put values into a structure



Is this statement accurate? The following processAnimals(List<? super Animal> animals) method allows me to get values out and put values in. Maybe it's just not advisable to get values out as Objects due to the possibility of ClassCastException. Similarly, it's not advisable to add null into List<? extends Animal> animals due to the possibility of NullPointerException.

 
Rico Felix
Ranch Hand
Posts: 411
5
IntelliJ IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tess Jacobs wrote:

Rico Felix wrote:Don’t use a wildcard when you want to both get values out and put values into a structure



Is this statement accurate? The following processAnimals(List<? super Animal> animals) method allows me to get values out and put values in. Maybe it's just not advisable to get values out as Objects due to the possibility of ClassCastException. Similarly, it's not advisable to add null into List<? extends Animal> animals due to the possibility of NullPointerException.



This argument was cleared up in my previous post (scroll 4 posts up from yours)
 
reply
    Bookmark Topic Watch Topic
  • New Topic