1

Why it doesn't work ?

class W<A extends Number>
   {
      public void create(A value)
      {

      }
   }

   public void calculate(W<? extends Number> w)
   {
      Integer v = 5;
      w.create(v); // Compilation error
   }

Could somebody explain what is wrong with that code and how to fix it?

Compilation error : "create (capture) in W cannot be applied to (java.lang.Integer)"

Yeynno
  • 331
  • 5
  • 10

5 Answers5

2

You have a common misconception about wildcards in generics. You think that ? means you can pass any type (as long as it extends Number), but you cannot.

? extends Number does not mean that you can pass any type that extends Number. It means "a specific, but unknown type that extends Number". Since the exact type is unknown to the compiler, it cannot allow you to use Integer - the compiler at that point simply has not enough information to check if it is type-safe. (It doesn't know if the actual type of the W that you pass to the method is Integer or some other type that extends Number).

This is exactly the same reason as why you cannot add anything to a List<?>, for example, which is a question that people often ask.

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • 2
    When it is asked so often, I am wondering why you are not duplicating this question to one of these many existing ones :-) – GhostCat Mar 10 '17 at 08:15
1

This follows straight from the core generics principle. When you use ? extends SomeType, you cannot pass/consume anything into the reference, as this might violate type safety guarantee provided by the Generics when retrieving these items. One would then be able to do -

List<Long> longs = Arrays.asList(5L, 10L, 20L);
List<? extends Number> numbers = longs;


// Trouble!
numbers.add(10.5);

See one of my blog posts here for details on how subtyping works with Generics.

MD Sayem Ahmed
  • 28,628
  • 27
  • 111
  • 178
0

You can use bounderies in the create method:

public <T extends Number> void  create(final T value) {

 }

Example:

class W<A extends Number> {
    public <T extends Number> void  create(final T value) {

    }

    public void calculate(final W<? extends Number> w) {
        final Integer v = 5;
        w.create(v); // Compilation error
    }
}
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
0

You have to declare what kind of W you're using before you use it

public void calculate(W<? extends Number> w) {
    Integer v = 5;
    new W<Integer>().create(v);
}

or, you can change the create method to accept any number

public void create(Number value) {

}
mike
  • 565
  • 1
  • 3
  • 18
-1

Both objects should extend Number, but that does NOT mean these objects cannot be siblings:

  • ClassA extends Number {..}
  • ClassB extends Number {..}

ClassA cannot be casted to ClassB, and this is what could happen in your code. It can be both ClassA but your compiler cannot be sure of that as it could be ClassB or any other class extending Number, so it gives a compile error.

Jeroen van Dijk-Jun
  • 1,028
  • 10
  • 22