TownCube
TownCube

Reputation: 1310

Parameterized method types not working when within in a List

When compiling this code:

private BiConsumer<MyObject, List<? extends MyOtherObject>> setter;

<T extends MyOtherObject> void setObject(BiConsumer<MyObject, List<T>> container) {
    this.setter = setter;
}

I get "Cannot convert from BiConsumer <MyObject, List<T>> to BiConsumer<MyObject, List<? extends MyOtherObject>>"

Based on the parameterized method I assumed the types are compatable, as T can only be something that extends MyOtherObject.

The other reason I think the types are correct is if I remove the List it works.

I'm not sure what it is about introducing the list that causes this error.

Upvotes: 0

Views: 67

Answers (2)

davidxxx
davidxxx

Reputation: 131326

What you want is a List which the generic is a upperbounded wildcard ofMyOtherObject :

void setObject(BiConsumer<MyObject, List<? extends MyOtherObject>> container) {
    this.setter = container;
}

With the scoped method T you defined as <T extends MyOtherObject>, the container parameter will take the type of the received argument and List<T> can be a different type from the List<? extends MyOtherObject> type.
For example it could be List<MyOtherObject> or List<MyOtherObjectOtherSubclass>. And the problem is that these cannot be assigned to List<? extends MyOtherObject> defined inside BiConsumer : a generic type variable.

You can check this behavior without using a method :

private BiConsumer<MyObject, List<? extends MyOtherObject>> setter;
...

BiConsumer<MyObject, List<? extends MyOtherObject>> listWildCard = ...;
this.setter = listWildCard; // compiles

BiConsumer<MyObject, List<MyOtherObject>> listSpecificType = ...;
this.setter = listSpecificType ; // doesn't compile

The other reason I think the types are correct is if I remove the List it works.

The error you encounter happens because your declared a generic type variable that declares itself a generic type and that you try to parameterize the type of the inner generic type. Making it is not valid because the parameter is so not a subtype of BiConsumer<MyObject, List<? extends MyOtherObject>> any longer.

With a simple List as parameter this code also would be fine :

private List<? extends MyOtherObject> setter;

<T extends MyOtherObject> void setObject(List<T> container) {
    this.setter = container;
}

Or by defining the whole parameter as a parameterized type, it would work too :

private List<? extends MyOtherObject> setter;

<T extends BiConsumer<MyObject, List<? extends MyOtherObject>>> void setObject(T container) {
    this.setter = container;
}

Upvotes: 4

Pedro
Pedro

Reputation: 1072

You need to define the generic at class level:

public class YourClass<T extends MyOtherObject> {
  private BiConsumer<MyObject, List<T>> setter;

  void setObject(BiConsumer<MyObject, List<T>> container) {
      this.setter = container;
  }
}

Otherwise there is no relationship between the generic T of the method and the wildcard of setter. They both extend MyOtherObject but they could be entirely different classes, which is why it won't compile.

Upvotes: 0

Related Questions