在看一些OOP材料时,我想到了这个让我感到困惑的问题:
考虑使用以下接口,抽象类和具体类:
package one;
public interface A {
void doStuff();
}
package one;
public abstract class B implements A {
public abstract void doStuff();
}
class C extends B{
public void doStuff() {
}
}
类 C 除非为方法doStuff()
提供实现,否则将无法编译。
这里的问题是:
1 - 类 C 中的doStuff()
方法是接口 A 方法的实现,或者是类 B ?更具体一点:JVM将如何
将函数视为接口或抽象类的调用函数?
2 - 抽象类 B 中的抽象方法doStuff()
被认为是接口 A 中doStuff()
方法的“实现” ?所以这使得 C 类必须实现抽象类的doStuff()
版本而不是接口的?
答案 0 :(得分:4)
对于问题#1:C类中的doStuff方法是对B和C的doStuff方法声明的实现,因为抽象类B和接口A中的doStuff方法声明具有彼此相同的签名。实际上,如果B实现C,则不需要再次声明doStuff方法。
对于问题#2:不,B中的doStuff只是一个声明,而不是方法实现。如果B没有方法实现或附加方法声明,则不需要B类。基本上,抽象类是一种包含高级逻辑的模板,以方便其子类。
答案 1 :(得分:1)
对于B类的例子,C.doStuff()重写B.doStuff()并实现A.doStuff()。虚拟地调用java中的所有方法。事实上,用户没有区别,无论C.doStuff()是否覆盖B的方法或A。对于jvm,它会有所不同,因为基于接口的调用与基于类的调用不同。
UPD:这取决于您要调用的链接类型。 javac将生成不同的opcoded:invokevirtual或invokeinterface
答案 2 :(得分:1)
在界面中,所有方法都是public
和abstract
。
了解这一点,界面A的doStuff实际上是 public abstract void doStuff()
。这应该看起来很熟悉,因为抽象类B具有相同的方法签名。
要回答问题1,B类的doStuff()
与接口A的doStuff()
是相同的。由于Java中的所有方法都是virtual,因此无论您的C是声明为A,B还是C,调用doStuff()
都是相同的。
关于问题2,没有。 B doStuff()
是冗余代码,实际上并没有做任何事情。 C正在实施A doStuff()
,无论B是否声明doStuff()
。
答案 3 :(得分:0)
如果删除
public abstract void doStuff();
在抽象类中,继承此类的子项必须实现此方法。
尝试在B类中删除此方法,并在C类中查看结果
参见抽象类在http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
中实现接口时的部分答案 4 :(得分:0)
我认为可以找到您正在寻找的解释here。
问题1:C类中的方法实现了两者。因为它只扩展了B,所以它只需要实现B抽象方法和未实现的接口。
问题2:它不被视为实施。抽象类不必实现所有接口方法。 C类的实施是强制性的(即使你没有在B类中有抽象的)。