我有以下情况:
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 {
}
以下是我的问题:
我知道实例方法会覆盖默认方法但是如果类中的静态方法与Interface中的默认方法具有相同的签名会怎样?
如果m1()
中的静态方法class C
是公开的,那么编译错误将是:
静态方法m1()与I中的抽象方法冲突。
因此,当访问修饰符是默认值时,它试图隐藏,当它是公共时,它是冲突的。为什么会有这种差异?它背后的概念是什么?
答案 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()
是静态的,无法覆盖,因此不能将其视为C
中m1()
的实现,因此编译问题。< / 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()
。