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

use*_*089 12 java inheritance multiple-inheritance default-method

我有以下情况:

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 {

}
Run Code Online (Sandbox Code Playgroud)

以下是我的问题:

  1. 我知道实例方法将覆盖默认方法,但是如果类中的静态方法与Interface中的默认方法具有相同的签名呢?

  2. 如果静态方法m1()class C将公共那么编译错误将是:

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

因此,当访问修饰符是默认值时,它试图隐藏,当它是公共时,它是冲突的.为什么会有这种差异?它背后的概念是什么?

Eug*_*ene 5

最终归结为这样一个事实:当你有这样的事情时:

class Me {
    public static void go() {
        System.out.println("going");
    }
}
Run Code Online (Sandbox Code Playgroud)

这两者都是允许的:

Me.go();
Me meAgain = new Me();
meAgain.go(); // with a warning here
Run Code Online (Sandbox Code Playgroud)

有趣的是,这也可以工作,例如:

Me meAgain = null;
meAgain.go();
Run Code Online (Sandbox Code Playgroud)

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

你的第一个问题与java-8本身无关,在java-8之前它是这样的:

interface ITest {
    public void go();
}

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

    }
}
Run Code Online (Sandbox Code Playgroud)

默认方法在这里遵循相同的规则。为什么会发生这种情况实际上在堆栈溢出上有很多详细说明 - 但潜在的想法是,这可能会导致调用哪个方法的混乱(想象一下,ITest将是一个Test会扩展的类,而您会这样做ITest test = new Test(); test.go(); -> 您正在调用哪个方法? )

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

static class Me {
    static void go() {

    }

    void go() {

    }
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)


cle*_*ens 0

因为java中的类方法也可以使用实例变量来调用,所以这种构造会导致歧义:

Main m = new Main();

m.m1();
Run Code Online (Sandbox Code Playgroud)

目前还不清楚最后一条语句应该调用类方法C.m1()还是实例方法I.m1()