为什么这个 class 不被视为超类型作为参数?

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

给出以下示例,为什么我可以将 return 类型 List<? extends IConfigUser> 覆盖为 getUserList() 中的 List<ConfigUser>,但不能对 setUserList()?

在这种情况下,ConfigUser 不被视为 IConfigUser 的超类型吗?

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

您可以通过向 IConfig 添加泛型类型参数来实现您的目标:

public class Test {
   public interface IConfigUser {
   }

   public interface IConfig<T extends IConfigUser> {
      public List<T> getUserList();
      public void setUserList(List<T> list);
   }


   public class ConfigUser implements IConfigUser {
   }

   public class Config implements IConfig<ConfigUser> {
      @Override
      public List<ConfigUser> getUserList() {
         return null;
      }

      @Override
      public void setUserList(List<ConfigUser> list)
      {
      }
   }
}

您可以 return 覆盖中的更具体类型,但不能要求您 接受更具体的类型。摆脱泛型,你可以用方法 returning String 覆盖方法 returning Object,但你不能覆盖接受 [=] 的方法11=] 参数和接受 String 参数的方法。

所有这一切都是为了让来电者兼容。考虑:

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

糟糕 - 您的 Config.setUserList 期望每个元素都是 ConfigUser,而不是 SomeOtherConfigUser

由于协方差,您可以 return ("specialize") getUserList() 的 return 类型,即如果您在 IConfig 引用上调用该方法你只知道你会得到一个 List<? extends IConfigUser> 和一个 List<ConfigUser> 是一个 List<? extends IConfigUser> 所以满足要求。

如果您在 Config 参考上调用它,则信息会更具体,但仍满足基本要求。

使用 setUserList(...) 情况不同:它允许您传递 任何 "subclass" of List<? extends IConfigUser> which can be a List<ConfigUser> 但它也可以是其他东西,例如List<SomeConfigUser>.

顺便说一句,因为您不知道 setUserList(List<ConfigUser> list)list 的具体通用参数,编译器也只允许您从该列表中读取,永远不会添加到它 - 同样原因如上:你不知道你得到了什么,也不知道是否允许添加 ConfigUser 因为列表只能允许添加 SomeConfigUser 个实例。