Why is this class not considered a supertype as a parameter?

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 {
      public List<ConfigUser> getUserList() {
         return null;

      // The method setUserList(List<ConfigUser> list) of type Test.Config
      // must override or implement a supertype method
      public void setUserList(List<ConfigUser> list)
Jon Skeet

You can return a more specific type in an override, but you can't require that you accept a more specific type. Get rid of the generics, and you can override a method returning Object with a method returning String, but you can't override a method accepting an Object parameter with a method accepting a String parameter.

All of this is so that callers are compatible. Consider:

IConfig config = new Config();    
List<SomeOtherConfigUser> list = new ArrayList<SomeOtherConfigUser>();
list.add(new SomeOtherConfigUser());

Oops - your Config.setUserList is expecting every element to be a ConfigUser, not a SomeOtherConfigUser.


See more on this question at Stackoverflow