The problem is that the type inference has been improved. You have a method like
public <T extends Base> T get() {
return (T) new Derived();
}
which basically says, “the caller can decide what subclass of Base
I return”, which is obvious nonsense. Every compiler should give you an unchecked warning about your type cast (T)
here.
Now you have a method call:
set(new Derived(), new Consumer().get());
Recall that your method Consumer.get()
says “the caller can decide what I return”. So it’s perfectly correct to assume that there could be a type which extends Base
and implement Collection
at the same time. So the compiler says “I don’t know whether to call set(Base i, Derived b)
or set(Derived d, Collection<? extends Consumer> o)
”.
You can “fix” it by calling set(new Derived(), new Consumer().<Derived>get());
but to illustrate the madness of your method, note that you can also change it to
public <X extends Base&Collection<Consumer>> void test() {
set(new Derived(), new Consumer().<X>get());
}
which will now call set(Derived d, Collection<? extends Consumer> o)
without any compiler warning. The actual unsafe operation happened inside the get
method.
So the correct fix would be to remove the type parameter from the get
method and declare what it really returns, Derived
.
By the way, what irritates me, is your claim that this code could be compiled under Java?7. Its limited type inference with nested method calls leads to treating the get
method in a nested invocation context like returning Base
which can’t be passed to a method expecting a Derived
. As a consequence, trying to compile this code using a conforming Java?7 compiler will fail as well, but for different reasons.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…