【问题标题】:Java 8 -Two interfaces contain default methods with the same method signature but different return types, how to override?Java 8 - 两个接口包含具有相同方法签名但返回类型不同的默认方法,如何覆盖?
【发布时间】:2018-05-31 01:43:33
【问题描述】:

我知道如果一个类实现了多个包含同名默认方法的接口,那么我们需要在子类中重写该方法,以便明确定义我的方法将做什么。
问题是,见下文代码:

interface A {
    default void print() {
        System.out.println(" In interface A ");
    }
}

interface B {
    default String print() {
        return "In interface B";
    }
}

public class C implements A, B {

    @Override
    public String print() {
        return "In class C";
    }

    public static void main(String arg[]) {
        // Other funny things
    }
}

现在接口 A 和 B 都有一个名为“print”的默认方法,但我想覆盖接口 B 的打印方法 - 返回字符串并保持 A 的打印不变的方法。但是这段代码不能编译给出这个:

Overrides A.print
The return type is incompatible with A.print()

显然编译器试图覆盖 A 的 print 方法,我不知道为什么!

【问题讨论】:

  • 狂想:改变“实现”列表的顺序
  • @flowtron 我的第一个直觉是一样的,不起作用。
  • 也许一个实现 A 并将其打印定义为 final 的类可以让你到达那里.. 另一个疯狂和 hack-y 的想法。
  • @flowtron 当然必须有其他方法解决这个问题,但我想知道为什么这个功能是这样设计的。

标签: java interface java-8 overriding default-method


【解决方案1】:

这是不可能的。

8.4.8.3:

如果返回类型为R<sub>1</sub> 的方法声明d<sub>1</sub> 覆盖或隐藏了返回类型为R<sub>2</sub> 的另一个方法d<sub>2</sub> 的声明,那么d<sub>1</sub> 必须是return-type-substitutable em> 为d<sub>2</sub>,或发生编译时错误。

8.4.5:

返回类型为R<sub>1</sub> 的方法声明d<sub>1</sub>return-type-substitutable,对于另一个返回类型为R<sub>2</sub> 的方法d<sub>2</sub>,如果以下任何一项为真: p>

  • 如果R<sub>1</sub>void,那么R<sub>2</sub>void

  • 如果R<sub>1</sub> 是原始类型,则R<sub>2</sub>R<sub>1</sub> 相同。

  • 如果R<sub>1</sub> 是引用类型,则以下情况之一为真:

    • R<sub>1</sub>,适配d<sub>2</sub>的类型参数,是R<sub>2</sub>的子类型。

    • R<sub>1</sub> 可以通过未经检查的转换转换为R<sub>2</sub> 的子类型。

    • d<sub>1</sub>d<sub>2</sub>R<sub>1</sub> = |R<sub>2</sub>| 的签名不同。

换句话说,void,返回原始和引用的方法只能覆盖和被同一相应类别的方法覆盖。 void 方法只能覆盖另一个 void 方法,引用返回方法只能覆盖另一个引用返回方法,依此类推。

解决您遇到的问题的一种可能方法是使用组合而不是继承:

class C {
    private A a = ...;
    private B b = ...;
    public A getA() { return a; }
    public B getB() { return b; }
}

【讨论】:

  • 我主要关心的是重写接口 B 的 'print()' 方法,你提到的链接确实很清楚地表明:It is a compile-time error if a class C inherits a concrete method whose signature is override-equivalent with another method inherited by C. 所以我理解“发生了什么”,但“为什么”还是不清楚!为什么编译器不能通过方法的签名识别我正在覆盖接口 B 的 print() 方法。或者,如果您能给我一些见解,为什么这是一种不好的做法?
  • @Radiodef:在类文件格式中可能的。所以是的,没有技术原因。
  • @RamanVerma:由于Java甚至不允许C类同时实现AB,所以它是否可以识别你是哪个方法无关紧要压倒一切。原因是当说someInstanceOfC.print() 时,它无法识别您调用 的方法,至少在Java 设计者不希望的方式改变语言规则的情况下无法识别。
  • @Eugene:对我来说,它看起来与原始 Java 语言的所有其他设计决策一致,以使其简单且不易出错。即使在存在目标类型的当前版本中,根据预期的返回类型在不同的方法中进行选择也不是一个好主意。
  • 再补充一点:根据返回类型选择方法肯定不能很好地适应协变返回类型。继承一个返回 Number 的方法和另一个返回 Integer 的方法会产生相当模糊的问题。如果你重写Integer-returning 方法,那会自动重写Number-returning 方法吗,或者你最终会得到两个方法?我很高兴不支持这种混乱。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-06
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多