当前位置: 首页 > 知识库问答 >
问题:

类中静态方法与接口中默认方法具有相同的签名

林星阑
2023-03-14

我有以下场景:

class C {
    static void m1() {}
}

interface I {
    default void m1() {}
}

//this will give compilation error : inherited method from C cannot hide public abstract method in I
class Main extends C implements I {

}

以下是我的问题:

如果类C中的静态方法M1()是公共的,则编译错误将为:

静态方法m1()与I中的抽象方法冲突。

因此,当访问修饰符是默认值时,它试图隐藏,而当它是公共的时,它是冲突的。为什么会有这样的区别呢?背后的理念是什么?

共有1个答案

杜祺
2023-03-14

归根结底,这可以归结为这样一个事实:

class Me {
    public static void go() {
        System.out.println("going");
    }
}

这两者都是允许的:

Me.go();
Me meAgain = new Me();
meAgain.go(); // with a warning here

有趣的是,这也会起作用,例如:

Me meAgain = null;
meAgain.go();

就我个人而言,我仍然认为这是一个设计缺陷,由于兼容性的原因而无法收回--但我希望编译器不允许我从实例访问静态方法。

您的第一个问题与java-8本身并不相关,在java-8之前就已经是这样了:

interface ITest {
    public void go();
}

class Test implements ITest {
    public static void go() { // fails to compile

    }
}

默认方法在这里遵循相同的规则。为什么会发生这种情况,实际上在堆栈溢出上有很多详细的说明--但其基本思想是,这可能会在调用哪个方法上造成混乱(假设itesttest将扩展的类,并且您执行itest test=new test();test.go();->您调用的是哪个方法?)

我认为出于同样的原因,这也是不允许的(这基本上是您的第二个问题,否则您将拥有一个具有相同签名的静态和非静态方法)

static class Me {
    static void go() {

    }

    void go() {

    }
}

有趣的是,这在方法引用中是固定的(我猜他们意识到再犯同样的错误真的很糟糕):

static class Mapper {
    static int increment(int x) {
        return x + 1;
    }

    int decrement(int x) {
        return x - 1;
    }
}


Mapper m = new Mapper();
IntStream.of(1, 2, 3).map(m::increment); // will not compile
IntStream.of(1, 2, 3).map(m::decrement); // will compile
 类似资料:
  • 当我注意到现在可以在接口中定义静态和默认方法时,我正在通过接口学习。 请解释两者的区别,如果有一个我们什么时候会使用它的例子,那就好了。界面上有点混乱。

  • 问题内容: 我有两个Java接口和一个实现类。 (我已经使用Eclipse直接运行程序,并且我没有尝试通过从命令行进行显式编译来检查任何编译器警告等)。 为什么它们运行没有问题?为什么Java允许这样做,即使它满足两个接口的“合同”,却在实现类时造成歧义? 更新了示例。 问题答案: Java语言规范的第8.1.5节专门允许这种情况: 类中的单个方法声明可以实现多个超级接口的方法。例如,在代码中:

  • 我试图使用以下代码理解Java接口中的默认方法,但我无法编译它: 编译器生成了以下输出: 我无法理解这些错误。我如何更正代码中的问题?

  • 在JLS 8第8.4.8.1节中,有一条声明: 在某些参数化下,泛型超类C中的具体方法可以与该类中的抽象方法具有相同的签名。在这种情况下,具体方法是继承的,而抽象方法不是。然后应将继承的方法视为覆盖其来自C的抽象对等体。 有人能为泛型类提供这种参数化的例子吗?我不能。

  • 问题内容: 假设我有两个接口: 如果我想同时实现它们,那么将使用哪种实现? 问题答案: 这是一个编译时错误。您不能从两个接口获得两个实现。 但是,如果在中实现该方法,则是正确的: 我只想补充一点,即使I1中的方法是抽象的,而I2中的方法是默认的,您也无法实现它们两者。因此,这也是一个编译时错误:

  • 问题内容: Java 8在接口上引入了默认方法和静态方法。因此,现在无论使用默认方法还是静态方法,您都可以在界面中实现具体的实现。 Java声称添加这两种新方法的原因是“确保与为那些接口的较旧版本编写的代码二进制兼容”。 我的问题: 为什么为了支持现有的体系结构问题而扭曲应该完全抽象的接口原始概念? 使用抽象类和新版本的接口之间的区别除了一个类具有扩展多个接口的能力之外,还有什么区别? 问题答案: