在 Java 中使用通用参数覆盖方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/239645/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:53:45  来源:igfitidea点击:

Overriding a method with Generic Parameters in Java?

javagenericsinheritance

提问by Robert Ngetich

I have an abstract Class Monitor.javawhich is subclassed by a Class EmailMonitor.java.

我有一个抽象类Monitor.java,它是由类EmailMonitor.java子类化的

The method:

方法:

public abstract List<? extends MonitorAccount> performMonitor(List<? extends MonitorAccount> accounts)

is defined in Monitor.javaand must be overridden in EmailMonitor.java.

Monitor.java 中定义并且必须在EmailMonitor.java 中覆盖。

I currently have the method overridden in EmailMonitor.javaas follows:

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

@Override
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
    //...unrelated logic
    return emailAccounts;
}

However, this produces the compile time error:

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

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

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

EmailAccountis a subclass of MonitorAccount, so (in my mind at least) overriding it in this way makes perfect sense. Seeing as the compiler is not happy with my logic though, How should I go about this correctly while still keeping my compile time checks to make sure that all calls to EmailMonitor.performMonitor()receive Lists of EmailAccountrather than some other type of MonitorAccount?

EmailAccount是 的子类MonitorAccount,所以(至少在我看来)以这种方式覆盖它是完全合理的。看到编译器对我的逻辑不满意,我应该如何正确地解决这个问题,同时仍然保持我的编译时检查以确保所有调用都是EmailMonitor.performMonitor()接收列表的EmailAccount而不是其他类型的MonitorAccount

采纳答案by Jon Skeet

No, it's not overriding it properly. Overriding means you should be able to cope with any valid input to the base class. Consider what would happen if a client did this:

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

Monitor x = new EmailMonitor();
List<NonEmailAccount> nonEmailAccounts = ...;
x.performMonitor(nonEmailAccounts);

There's nothing in there which should give a compile-time error given your description - but it's clearly wrong.

根据您的描述,那里没有任何东西应该给出编译时错误 - 但这显然是错误的。

It sounds to me like Monitorshould be generic in the type of account it can monitor, so your EmailMonitorshould extend Monitor<EmailAccount>. So:

在我看来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
    }
}

You might want to think carefully about the generics in the performMonitorcall though - what's the return value meant to signify?

不过,您可能需要仔细考虑performMonitor调用中的泛型——返回值意味着什么?

回答by Robert Ngetich

Here is my own solution. I suspect this is the same thing Jon Skeet was trying to get at... without the typo (see my comment in reply to his answer).

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

the Monitor.javaclass:

Monitor.java类:

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

EmailMonitor.java

电子邮件监视器.java

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

In this configuration, EmailMonitor.performMonitor()will always check at compile time that it receives a list of EmailAccountrather than any of my other types FTPAccount, DBAccount,etc... It's much cleaner than the alternative, which would have been receiving/sending a raw list and then having to coerce it the required type resulting in potential runtime type casting exceptions.

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