用Java中的泛型参数覆盖方法?

Rob*_*ich 42 java generics inheritance

我有一个抽象类Monitor.java,它由Class EmailMonitor.java子类.

方法:

public abstract List<? extends MonitorAccount> performMonitor(List<? extends MonitorAccount> accounts)
Run Code Online (Sandbox Code Playgroud)

Monitor.java中定义,必须在EmailMonitor.java中重写.

我目前在EmailMonitor.java中重写了如下方法:

@Override
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
    //...unrelated logic
    return emailAccounts;
}
Run Code Online (Sandbox Code Playgroud)

但是,这会产生编译时错误:

Name clash: The method performMonitor(List<EmailAccount>) of type EmailMonitor has the same erasure as performMonitor(Lis<? extends MonitorAccount> emailAccounts) of type Monitor but does not override it

EmailAccount是一个子类MonitorAccount,所以(至少在我看来)以这种方式覆盖它是完全有道理的.虽然编译器对我的逻辑不满意,但是如何在保持编译时检查以确保所有调用EmailMonitor.performMonitor()接收列表EmailAccount而不是其他类型的MonitorAccount

Jon*_*eet 34

不,它没有正确地覆盖它.覆盖意味着您应该能够处理基类的任何有效输入.考虑如果客户端这样做会发生什么:

Monitor x = new EmailMonitor();
List<NonEmailAccount> nonEmailAccounts = ...;
x.performMonitor(nonEmailAccounts);
Run Code Online (Sandbox Code Playgroud)

根据你的描述,那里没有什么应该给出编译时错误 - 但这显然是错误的.

听起来我觉得Monitor它可以监控的帐户类型应该是通用的,所以你EmailMonitor应该扩展Monitor<EmailAccount>.所以:

public abtract class Monitor<T extends MonitorAccount>
{
    ...
    public abstract List<? extends T> performMonitor(
        List<? extends T> accounts);
}

public class EmailMonitor extends Monitor<EmailAccount>
{
    @Override
    public abstract List<? extends EmailAccount> performMonitor(
        List<? extends EmailAccount> accounts)
    {
        // Code goes here
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能想要仔细考虑performMonitor电话中的泛型- 返回值意味着什么?


Rob*_*ich 9

这是我自己的解决方案.我怀疑这与Jon Skeet试图解决的问题是一样的......没有错字(请参阅我对回答的评论).

Monitor.java类:

public abstract class Monitor <T extends MonitorAccount> {
  ...
  public abstract List<T> performMonitor(List<T> accounts);
  ..
}
Run Code Online (Sandbox Code Playgroud)

EmailMonitor.java

public class EmailMonitor extends Monitor<EmailAccount> {
  ...
  public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
    ..//logic...logic...logic
    return emailAccounts;
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

在这个配置中,EmailMonitor.performMonitor()将始终在编译时检查它收到的EmailAccount列表而不是我的其他任何类型的FTPAccount,DBAccount等...它比替代方案更清晰,它本来就是接收/发送原始列表,然后必须强制它所需的类型,从而导致潜在的运行时类型转换异常.