【问题标题】:Java name clash error, a method has the same erasure as another methodJava名称冲突错误,一个方法与另一个方法具有相同的擦除
【发布时间】:2017-12-09 21:26:27
【问题描述】:

我有两个类如下

类查询结果:

public class QueryResult
{
...
public static List sortResults(boolean ascending, List<QueryResult> toSort)
    {   ...
    }
}

和类CaseResult:

public class CaseResult extends QueryResult
{
...
public static List sortResults(boolean ascending, List<CaseResult> toSort)
    {   ...
    }
}

我收到以下错误:

名称冲突:类型的方法 sortResults(boolean, List) CaseResult 与 sortResults(boolean, List) 类型为 QueryResult 但不隐藏 它是 CaseResult.java

我尝试了类似问题Java generics name clash , has the same erasure 下的答案,但出现了更多错误。我想我可能会误解某些东西,或者这些答案不适合我的情况。

有人可以提供任何解决方案或解释更多以帮助我理解吗?谢谢大家。

【问题讨论】:

  • 解决方案是为方法使用不同的名称,问题是您提供的 static 方法在类型擦除后具有相同的签名,因此在编译时无法选择 CaseResult.sortResults(...) 实现,或者更确切地说,即使可能,编译器也不是为了找到正确的实现而设计的,请检查:stackoverflow.com/questions/14002965/…
  • 感谢您的解释,@Jack。它是一个从网站下载的大型开源框架,因此在我的情况下,重命名方法可能会弄乱整个系统。如果找不到其他解决方案,我会尝试重命名。
  • @KenrySanchez,我尝试在 CaseResult 下的 sortResults 函数中添加 super(),但没有成功。也许我用错了。你能解释一下吗?谢谢。

标签: java generics inheritance compiler-errors name-clash


【解决方案1】:

根据Java Documentation,

如果子类定义了与父类中的静态方法具有相同签名的静态方法,则子类中的方法会隐藏超类中的方法。

隐藏静态方法和覆盖实例方法之间的区别具有重要意义:

  • 被调用的重写实例方法的版本是子类中的版本。
  • 被调用的隐藏静态方法的版本取决于它是从超类调用还是从子类调用

【讨论】:

  • 谢谢。你的解释有帮助。您对我的情况有详细的解决方案吗?
  • @Catherine 如果您想保留此结构并且不想更改您的方法名称,那么您可以创建一个接口,实现它并将其用作您的方法中的列表参数类型两个班。或将子类中的列表参数类型更改为父类。我希望明白我的意思。
  • 知道了。我会试一试。谢谢。
【解决方案2】:

Darshit Chokshi 的回答中涵盖了错误的原因。 但是,由于尚未发布解决方案/替代方案,请尝试以下操作:

您正试图以这样一种方式覆盖 sortResults() 方法,以便您可以对具有不同元素的列表进行排序。但是,在覆盖时,您需要具有相同的类型签名。在您的情况下,签名看起来很相似,但是由于 List 中的元素不同 - 编译器意识到 List 和 List 是不同的,但是由于 Java 中的类型擦除,不确定应该调用哪个方法- 即它应该调用超类方法还是子类方法。

与其重写,不如更改超类中的原始方法(在您的情况下为 QueryResult),以便它可以处理任何类型的 List 元素。您可以使用通配符捕获来完成此操作:

public class QueryResult {
...
public <T> static List<T> sortResults(boolean ascending, List<T> toSort) {   
    ...
    }
}

此方法接收一个列表并将推断元素类型,将元素类型分配给泛型类型参数 T。当您想要在方法体中引用元素类型时,而不是使用元素类型名称(以前是 QueryResult 或 CaseResult),现在您将使用泛型类型变量 T。

如果需要,您还可以对该变量设置进一步的界限(即,如果列表元素需要是 QueryResult 的子类型,您可以说 ),这将强制 Java 对 List 进行类型检查并它可能有什么类型的元素。

对您的原始代码的进一步评论。在新的通用代码中使用原始类型时要非常小心 - 您将列表作为原始类型返回:List,而没有指定列表的元素类型是什么,即参数化类型:List。这可能会导致许多问题,因此不建议这样做。 Java 的创建者在 Java 中保留了这种形式的编码,以便向后兼容泛型之前存在的代码,但强烈建议不要以这种方式编码新的书面代码。

您可以在教科书中详细了解原始类型与参数化类型以及使用原始类型的陷阱,以及有关通配符捕获和边界的更多信息:

Effective Java, by Joshua Bloch
    Section: Generics
    Item 23: Don't use raw types in new code
    Item 28: Use bounded wildcards to increase API flexibility

【讨论】:

  • 另一种选择是使用 QueryResult 中的所有方法创建一个接口 Result。 Result 类将具有方法:public static List sortResults(boolean ascending, List toSort)。然后有:QueryResult 实现 Result 和 CaseResult 实现 Result。然后,您可以保留您发布的原始代码。使用接口通常是比继承更好的设计选择。
猜你喜欢
  • 2011-01-01
  • 2018-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多