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



我有以下情况:

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. 我知道实例方法将覆盖默认方法,但是如果类中的静态方法与接口中的默认方法具有相同的签名怎么办?

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

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

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

最终,这归结为这样一个事实,即当你有这样的东西时:

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
}
}

默认方法在这里遵循相同的规则。为什么会发生这种情况实际上在堆栈溢出上有很多详细说明 - 但基本的想法是,这可能会导致对调用哪个方法的混淆(想象一下ITest会是一个Test会扩展的类,而你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

回答您的第一个问题:

"类中的静态方法">

和"接口中的默认方法"都可用于类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();
}
}

输出:m1 from I

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

回答你的第二个问题:

如果分类和接口位于同一包中,则默认和公共访问修饰符的工作方式应类似。

此外,C中的m1()是静态的,不能被覆盖,因此不能将其视为Im1()的实现,因此是编译问题。

希望对您有所帮助!

我将回答您的第一个问题,因为第二个问题已经回答

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

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

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

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

Main m = new Main();
m.m1();

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

相关内容

  • 没有找到相关文章

最新更新