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

时间:2017-08-09 05:16:57

标签: 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 {

}

以下是我的问题:

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

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

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

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

4 个答案:

答案 0 :(得分:4)

归根结底,当你有这样的事情时,

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

这两个都是允许的:

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

Intersting就是这样,例如:

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

    }
}

默认方法只是遵循相同的规则。为什么会发生这种情况实际上是关于堆栈溢出的详细信息 - 但潜在的想法是可能这会导致混淆调用哪个方法(想象ITest将是Test的类1}}会扩展,你做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

答案 1 :(得分:1)

回答你的第一个问题:

"类中的静态方法"接口"中的"默认方法;类 In[7]: best_ans Out[7]: ['a'] 可用,因此如果它们具有相同的签名,则会产生歧义。

例如:

Main

输出:class C{ static void m1(){System.out.println("m1 from C");} } public class Main extends C{ public static void main(String[] args) { Main main=new Main(); main.m1(); } }

类似地,

m1 from C

输出:interface I{ default void m1(){System.out.println("m1 from I");} } public class Main implements I{ public static void main(String[] args) { Main main=new Main(); main.m1(); } }

如您所见,这两个都可以类似地访问。因此,当您实现I并扩展C时,这也是冲突的原因。

回答你的第二个问题:

如果您的被分类和接口在同一个包中,则默认和公共访问修饰符应该类似。

此外,m1 from I中的m1()是静态的,无法覆盖,因此不能将其视为Cm1()的实现,因此编译问题。< / p>

希望有所帮助!

答案 2 :(得分:1)

我会回答你的第一个问题,因为第二个问题已经回答了

  

我知道实例方法会覆盖默认方法但是   如果类中的静态方法与默认方法具有相同的签名,该怎么办   在界面?

我假设您使用的是JDK 1.8,因此存在混淆。接口方法中的default修饰符并未讨论其访问规范。相反,它提到接口本身需要实现此方法。该方法的访问规范仍然是公开的。从JDK8开始,接口允许您使用默认修饰符指定方法,以允许以向后兼容的方式扩展接口。

在您的界面中,您必须提供default void m1() {}才能使编译成功。通常我们只是在接口中以类似void m1();的抽象方式定义它们您必须实现该方法,因为您将方法指定为默认方法。希望你明白。

答案 3 :(得分:0)

因为java中的类方法也可以使用实例变量调用,所以这个结构会导致含糊不清:

Main m = new Main();

m.m1();

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