Given the following example, why am I able to override the return type List<? extends IConfigUser> as List<ConfigUser> in getUserList() but cannot do the same for the parameter of setUserList()?
Isn't ConfigUser considered a supertype of IConfigUser in this case?
public class Test {
public interface IConfigUser {
}
public interface IConfig {
public List<? extends IConfigUser> getUserList();
public void setUserList(List<? extends IConfigUser> list);
}
public class ConfigUser implements IConfigUser {
}
// The type Test.Config must implement the inherited abstract method
// Test.IConfig.setUserList(List<? extends Test.IConfigUser>)
public class Config implements IConfig {
@Override
public List<ConfigUser> getUserList() {
return null;
}
// The method setUserList(List<ConfigUser> list) of type Test.Config
// must override or implement a supertype method
@Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
You can return ("specialize") the return type of
getUserList()due to covariance, i.e. if you call that method on aIConfigreference all you know is that you'll get aList<? extends IConfigUser>and aList<ConfigUser>is aList<? extends IConfigUser>so the requirements are satisfied.If you call that on a
Configreference the information is more concrete but the basic requirements are still met.With
setUserList(...)the situation is different: it allows you to pass any "subclass" ofList<? extends IConfigUser>which can be aList<ConfigUser>but it also can be something else, e.g. aList<SomeConfigUser>.Btw, since you don't know the concrete generic parameter of
listinsetUserList(List<ConfigUser> list)the compiler will also only allow you to read from that list, never add to it - for the same reason as above: you don't know what you get and whether adding aConfigUseris allowed because the list could only allowSomeConfigUserinstances to be added.