[英]Why interface methods have no body
要实现多重继承,我们必须使用接口,但为什么接口方法没有实体,为什么必须在派生类中重写它们?
我真的想要一个清醒的答案,不涉及太多的计算机术语,我似乎无法理解这一点,我已经提到了各种参考
因为Java与C ++或Eiffel之类的语言相比,只有多种类型的继承(即接口和一个类),而不是状态和行为的多重继承。 后者增加了巨大的复杂性(尤其是国家)。
Java设计者(和C#,就此而言)选择不包括它,因为它给C ++程序员带来了非常难以调试的问题。 通过实现多个接口,您可以解决几乎所有需要真正多重继承的问题,因此权衡被认为是值得的。
请注意, 行为 (非状态)的多重继承可能以虚拟扩展方法的形式出现在Java 8中(除非它们像许多其他事物中的一样再次推迟),其中接口可以声明委托给另一个类中的一个的方法,然后存在于实现该接口的所有类型上。
接口声明实现类提供的WHAT服务,而不是HOW(这是实现类的工作)。 多重继承被认为是不好的,因为它导致复杂的代码和类层次结构。
接口只有常量变量(public + static + final)和抽象方法(public和abstract)。 这些应该由实现接口的类使用。
接口简单地说'Am a contract',如果你想使用它,应该坚持一些规则(给所有抽象方法实现)。
Java中省略了多重继承,确保类只能扩展1个类,以避免钻石问题 。 无论如何,您可以通过使用接口在Java中进行多种类型的继承。
Java接口包含必须由实现接口的类实现的方法列表。 因此,方法没有主体:每个方法的主体都在实现类中。
简单回答:
接口提供了实现标准。
说明:
在Java中,接口类似于抽象类,因为其成员未实现 。 例如,
public interface Comparable
{ boolean less(Object m);
boolean greater(Object m);
boolean lessEqual(Object m);
boolean greaterEqual(Object m);
}
接口提供了实现标准。
使用接口的好处是它们模拟多重继承 。 Java中的所有类都必须只有一个基类 ,唯一的例外是java.lang.Object
(Java类型系统的根类); java中不允许多继承类。
所有实例方法都是隐式public
和abstract
。 您可以将它们标记为这样,但不鼓励这样做,因为标记被认为是过时的做法 。 接口本身不需要是公共的,标准库中的几个接口不是公共的,因此仅在内部使用。
接口创建类可以实现的协议 。 需要注意的是一个可扩展的接口(以获得一个新的接口),就像你可以扩展一个类 。 实际上可以扩展几个接口 。 接口因此享有多重继承的好处。 ( 类没有。)接口的多重继承几乎没有缺点 ( 小名称冲突问题是一个例外)。 与C++
一样,多重继承实现存在很大的缺点 。 这些包括效率考虑因素以及确定在某些情况下将执行哪些代码的语义难度。
实现Comparable的Polynomial类需要实现接口中声明的所有函数。
public class Polynomial implements Comparable
{ . . .
boolean less(Object m){ . . . }
boolean greater(Object m){ . . . }
boolean lessEqual(Object m){ . . . }
boolean greaterEqual(Object m){ . . . }
Polynomial multiply(Polynomial P){ . . . }
. . .
}
类可以选择实现任意数量的接口。 实现接口的类必须为该接口的所有方法提供实体。 此外,我们希望抽象类可以选择实现接口的一部分,其余部分用于非抽象子类。
接口的用处不仅仅是为其他程序员发布协议。 任何函数都可以具有接口类型的参数。 实现接口的类中的任何对象都可以作为参数传递。
接口方法没有体形
public interface Flyable
{
public void fly();
}
因为界面本身不会做任何事情
接口是定义合同。
另一方面,界面定义了一个类可以做什么,而不是它是什么。 所以界面通常是动词。
所以Flyable接口什么也没做,只是定义了植入的FlyableObjects将要飞的合同。
喜欢:
class Rocket implements Flyable
{
public void fly()
{
// do the stuffs.
}
}
当然,我们也只能通过接口实现多重继承。
如果界面有身体那么它会带回致命的Daimond of Death问题。
考虑这个与主体接口的例子
interface A {
void print(){ System.out.print("A") }
}
interface B {
void print(){ System.out.print("B") }
}
interface C extends A, B {
// now since A and B have bodies interfaces would have had choice to not to override the default behavior
}
public class C_Implementer implements C{
public static void main(String args[]){
C c = new C_Implementer();
c.print(); // gotcha!!!!! what should it print, A or B????
}
}
您在问“为什么Java不支持多重继承实现?”
这在Java教程,状态的多重继承,实现和类型中讨论 ,但我想给出一个实现的多重继承问题的特定示例(以及最后的新语言特性解决方案)。
想象一下两个接口(在我们提出的允许接口方法体的Java版本中)定义一个具有相同名称的方法。
public interface FaceOne {
public void method() {
System.out.println("FaceOne Version");
}
}
public interface FaceTwo {
public void method() {
System.out.println("FaceTwo Version");
}
}
并且类实现两个接口,但不会覆盖该方法。
public class Inheriter implements FaceOne, FaceTwo {
}
当我调用Inheriter.method()
,由于该类从其祖先继承了该方法,因此会出现问题:输出是否打印“FaceOne Version”或“FaceTwo Version”?
另外,如果类要覆盖该方法,但又想使用super
调用其祖先的版本,则编译器将再次无法在该方法的版本之间进行选择。
这就是Java不支持多重继承实现的原因。
顺便说一句,我认为在语言中实现这一点的一种优雅方式如下:
继续强制实现类来覆盖其祖先接口的方法。 这解决了非重写方法的第一个问题。
然后,使用与访问内部类的封闭实例相似的表示法来访问具有super
的特定祖先接口。 然后,Inheriter类将有多个选项:
不要调用super.method()
,而只使用新定义的实现。
使用FaceOne.super.method()
使默认继承的实现输出“FaceOne Version”。
使用FaceTwo.super.method()
使默认的继承实现输出“FaceTwo Version”。
使用以上组合:
一种实现可能是:
@Override
public void method() {
FaceOne.super.method();
FaceTwo.super.method();
System.out.println("Inheriter Version");
}
输出:
FaceOne版本
FaceTwo版本
继承人版本
编辑:根据这个问题,这显然是如何在Java 8中构建默认实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.