javaoverridingsupertype

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 {
      @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)
      {
      }
   }
}

Solution

  • You can return ("specialize") the return type of getUserList() due to covariance, i.e. if you call that method on a IConfig reference all you know is that you'll get a List<? extends IConfigUser> and a List<ConfigUser> is a List<? extends IConfigUser> so the requirements are satisfied.

    If you call that on a Config reference 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" of List<? extends IConfigUser> which can be a List<ConfigUser> but it also can be something else, e.g. a List<SomeConfigUser>.

    Btw, since you don't know the concrete generic parameter of list in setUserList(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 a ConfigUser is allowed because the list could only allow SomeConfigUser instances to be added.