Reputation: 8497
I would like to take the contents of the G.myUglyList list here and pass it to the Outer.send() method. I do not understand why this gives a compiler error. ? extends Inner is the type I parameterize Outer with. So why is it rejecting an Inner passed to it? It wants a "? extends Inner", which isn't a type.
I want the list declared as List<Outer<? extends Inner>>
so it can take subtypes of Inner. (Please see the edit below for why this is)
interface Outer<T> {
void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}
public class G {
List<Outer<? extends Inner>> myUglyList;
void foo() {
Inner xxx = null;
for (Outer<? extends Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}
I get this error:
error: method send in interface Outer<T#2> cannot be applied to given types;
required: CAP#1
found: Inner<T#1>
reason: actual argument Inner<T#1> cannot be converted to CAP#1 by method invocation conversion
where T#1,T#2 are type-variables:
T#1 extends Object declared in class G
T#2 extends Object declared in interface Outer
where CAP#1 is a fresh type-variable:
CAP#1 extends Inner<T#1> from capture of ? extends Inner<T#1>
edit: I got a lot of answers saying just make the list of type List<Outer<Inner>>
, but that is incorrect. I will not be able to add subtypes of Inner if I do that. If I try to add an Outer<Inner2>
, it would fail. So list must be of type List<Outer<? extends Inner>>
.
interface Inner2 extends Inner {}
class G {
void foo() {
Outer<Inner2> foiled = null;
myUglyList.add(foiled); //this will fail if list is of type List<Outer<Inner>>
Inner xxx = null;
for (Outer<? extends Inner> outer : myUglyList) {
outer.send(xxx); //error
}
Upvotes: 3
Views: 1407
Reputation: 122518
PECS - Producer extends
Consumer super
Because outer
is parameterized with extends
, you cannot pass anything (except null
) into its send
method.
Upvotes: 1
Reputation: 16059
Change your code for:
interface Outer<T> {
void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}
public class G {
List<Outer<Inner>> myUglyList;
void foo() {
Inner2 xxx = null;
for (Outer<Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}
And it will compile
Update:
// No matter if you put 'T extends Inner' here, the 'add' won't compile
interface Outer<T extends Inner> {
void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}
public class G {
List<Outer<Inner>> myUglyList;
void foo() {
Outer<Inner2> foiled = null;
// This way, the 'add' invocation will compile, but it
// breaks the generic and generates a warning.
//
// Casting 'foiled' to (Outer<Inner>) will also fail
// because the compiler sees Outer<Inner2> as complete different type
// from Outer<Inner>
myUglyList.add((Outer) foiled);
Inner xxx = null;
for (Outer<Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}
Upvotes: 3
Reputation: 51030
for (Outer<? extends Inner> outer : myUglyList) {
outer.send(xxx); //error
}
In that, Outer<? extends Inner> outer
, so the actual type is unknown (?
). send
takes something unknown that extends Inner
, and also outer
has something that extends Inner
but still unknown.
Update
interface Outer<T extends Inner> {
void send(T message); //this can take instance of subtype of Inner
}
interface Inner {}
interface Inner2 extends Inner {}
class G {
List<Outer<Inner>> myUglyList; //you can add instances of subtypes of Inner
void foo() {
Inner xxx = null;
for (Outer<Inner> outer : myUglyList) {
outer.send(xxx); //error
}
}
}
Upvotes: 1
Reputation: 28761
outer
is of type Outer<? extends Inner>
, i.e. of some unknown subtype of Inner
and its send
method takes an object of that same subtype.
For example outer
may be of type Outer<OtherInner>
and then outer.send
needs a OtherInner
, so outer.send(xxx)
would be wrong.
Upvotes: 2
Reputation: 234857
Just declare
List<Outer<Inner>> myUglyList;
You can then add subtypes of Inner
without restriction. By declaring it
List<Outer<? extends Inner>> myUglyList;
you are saying that myUglyList
is "a list of Outer<some specific (but unknown) subtype of Inner>
". That's not what you want.
Upvotes: 2