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

时间:2017-11-29 11:05:01

标签: java override supertype

鉴于以下示例,为什么我能够在List<? extends IConfigUser>中将返回类型List<ConfigUser>覆盖为getUserList(),但不能对setUserList()的参数执行相同操作?< / p>

在这种情况下,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)
      {
      }
   }
}

3 个答案:

答案 0 :(得分:2)

您可以通过向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)
      {
      }
   }
}

答案 1 :(得分:2)

您可以在覆盖中返回更具体的类型,但不能要求接受更具体的类型。摆脱泛型,您可以使用返回Object的方法覆盖返回String的方法,但是您无法覆盖接受Object参数的方法并接受方法一个String参数。

这一切都是为了使呼叫者兼容。考虑:

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

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

答案 2 :(得分:1)

由于协方差,您可以返回(“specialize”)getUserList()的返回类型,即如果您在IConfig引用上调用该方法,您所知道的就是您将得到List<? extends IConfigUser> 1}}和List<ConfigUser> List<? extends IConfigUser>,因此满足要求。

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

使用setUserList(...)情况有所不同:它允许您传递 List<? extends IConfigUser>的任何“子类”,其中可以 a {{1但它也可能是其他东西,例如List<ConfigUser>

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