1

The recurring explanation I find is that an upper bounded wildcard relaxes the restrictions of types that a type parameter can accept. This concept applies to bounded generics as well, for example:

static <T extends Number> void gMethod (ArrayList <T> list) {}

This method's generic will accept Objects of type Number or any of it's sub classes when specified:

ArrayList <Integer> intList = new ArrayList();
gMethod(intList); // allowed

For further elaboration that a generic bounded to Number will accept type arguments of Number or any of it's sub classes as well:

class Thing <T extends Number> {}
Thing <Number> numThing = new Thing();
Thing <Integer> intThing = new Thing();
Thing <Double> dubThing = new Thing(); // All three instances work

Given this, the only benefit I can see to using an upper bounded wildcard vs a bounded generic is that an upper bounded wildcard type argument can be declared without relying on a type parameter already declared by either a class or method. Is there a more important benefit that I'm missing?

Matthew S.
  • 464
  • 2
  • 12
  • You don't show any example of bounded wildcard... – ernest_k Nov 27 '19 at 17:38
  • 2
    Yes, it's just a parameter that you didn't want to bother naming. No need to invent a name that will only be used once. – Matt Timmermans Nov 27 '19 at 17:38
  • If anyone is wondering, this seems to be the primary benefit (if not the only) to using wild cards in general. I just so happened to have this question while messing with upper bound wild cards – Matthew S. Nov 28 '19 at 13:01
  • I see a few more reason, but I am not sure they count as an answer. 1) it depends on what you want to do with this `list`. can you put something into it if this is a wildcard? 2) if you really don't care about `T` (I mean you would not use any variable as `T` type internally in the method), then there is that general advice to get rid of it and use a `wildcard` 3) wildcards can have a single bound, while type references can have more (this matter when the raw/erased type is derived) 4) I find myself into a position to introduce a wildcard when I already have a type argument and don't want – Eugene Jul 27 '20 at 13:43
  • to introduce another one. For example: `public void(List extends T>)`. I could use `List`, but that would mean I need to introduce one more type argument and that will make little sense to the callers, probably. As said, I don't really know if this answers your question. – Eugene Jul 27 '20 at 13:45

1 Answers1

0

…the only benefit I can see to using an upper bounded wildcard vs a bounded generic…

If your use case only ever calls for you working with one Thing at a time, then the simple usage scenario you outline is all you'll ever need.

But eventually you'll have a use case where you will need to work with a heterogeneous assortment of Things. That's when you'll need to pull slightly more advanced polymorphism out from your toolbox.

…Is there a more important benefit that I'm missing?…

One super important benefit that it sounds like you're missing is a substitutability relationship between types; called covariance.

For example, since it's legal to do this:

Integer[] intAry = {2,4,6,8};
Number[] numAry = intAry;
    

Then intuitively, it seems like you should be able to do this:

List<Integer> intList = List.of(8,6,7,5,3,0,9);
List<Number> numList = intList; // but this fails to compile

A wildcard with an upper bound effectively makes collections covariant:

List <? extends Number> numList = intList;

Since Integer extends Number :

Thing<Number> numThing = new Thing<>();
Thing<Integer> intThing = new Thing<>();

Then intuitively, it seems like you should be able to do this:

numThing = intThing; // but this fails to compile

A wildcard with an upper bound effectively makes Things more intuitive:

Thing<? extends Number> numThing = new Thing<>();        
numThing = intThing; /* That makes sense! */

Same deal with methods. With this declaration:

public static void use(Thing<Number> oneThing){ 
    /*...*/
}

This would fail to compile:

Thing<Integer> intThing = new Thing<>();        
use(intThing); /*  error: no suitable method found for use(Thing<Integer>) */

Wild cards with upper bounds makes it possible to use Things the way you intuitively would think they'd be used:

public static void use(Thing<? extends Number> anyThing){ 
    /* ...*/
}

...
Thing<Integer> intThing = new Thing<>();        
use(intThing); /* Perfectly fine! */

…applies to bounded generics…This method's generic will accept…an upper bounded wildcard vs a bounded generic

The things you've incorrectly called „generics“ are actually called either type parameters, type variables or type arguments; depending on the context.

deduper
  • 1,944
  • 9
  • 22
  • I should have been clearer in my question. My question pertains to the function of type arguments in a method signature, none of these examples address my question. I'm comparing the function of a paramterized method argument that has a type argument of bounded wildcard to a paramterized method argument with a type argument of bounded type parameter. In your last code snippet, you can replace the bounded wildcard with a bounded type parameter and, bounds being the same, the result would be the same. There doesn't seem to be any advantage of one over the other besides the brevity of wildcards – Matthew S. Jul 18 '20 at 17:43
  • „*...There doesn't seem to be any advantage of one over the other besides the brevity of wildcards...*“ — If you say so, chief. – deduper Jul 18 '20 at 23:52
  • 1
    If you think there is a benefit feel free to share. However, I don't think you understand what covariance is. Both wildcards and type parameters implement covariance identically, the only difference between wildcards and type parameters in terms of variance is that wildcards are contravariant as well, making them bivariate. Don't worry about it though, generics in general is confusing I'm sure you'll get the hang of it – Matthew S. Jul 19 '20 at 16:30