interface CanFight {
void fight();
}
interface CanSwim {
void swim();
}
interface CanFly {
void fly();
}
class ActionCharacter {
public void fight() {
System.out.println("Inside class fight");
}
}
class Hero extends ActionCharacter
implements CanFight, CanSwim, CanFly {
public void swim() {}
public void fly() {}
}
public class MultipleInterface {
public static void t(CanFight x) { x.fight(); }
public static void u(CanSwim x) { x.swim(); }
public static void v(CanFly x) { x.fly(); }
public static void w(ActionCharacter x) { x.fight(); }
public static void main(String[] args) {
Hero h = new Hero();
t(h); // Treat it as a CanFight
u(h); // Treat it as a CanSwim
v(h); // Treat it as a CanFly
w(h); // Treat it as an ActionCharacter
}
}
JVM如何表现,因为我没有从canFight
接口实现方法,但它是从ActionCharacter
类获取的?它背后的逻辑是什么?要点是我没有定义在实现fight()
接口时必须完成的方法canFight()
。
答案 0 :(得分:3)
这不是JVM,而是Java编译器。 (如果JVM发现丢失的方法应该存在,那么你会得到一个NoSuchMethodException,但编译器不会让你达到那个点,除非你欺骗它。)
至于你的问题,声明方法的类或超类或接口无关紧要,只需要匹配名称和签名。因此,ActionCharacter#fight
和CanFight#fight
声明了同样的事情。 Java没有区分这两者(既不是编译器也不是JVM /字节码格式)。
您的Hero
从fight
继承了ActionCharacter
,但由于它恰好也与CanFight
中定义的方法相匹配,因此它也可以兼作该接口的实现。< / p>
可以更清楚地更改方法名称(如果这些应该是两种不同的方法)或者ActionCharacter
也实现CanFight
(如果这确实是相同的方法)。
答案 1 :(得分:2)
如果一个类型实现了两个接口,并且每个接口定义了一个具有相同签名的方法,那么实际上只有一个方法,并且它们是不可区分的。
如果两个方法的返回类型相互冲突,则会出现编译错误。这是继承,方法重写,隐藏和声明的一般规则,并且还适用于不仅可能在2个继承的接口方法之间发生冲突,还可以应用于接口和超类方法之间的冲突,甚至只是由于泛型的类型擦除引起的冲突
在JLS
中说允许类中的单个方法声明 实现多个超接口的方法。
答案 2 :(得分:1)
您正在扩展ActionCharacter
,这意味着您希望ActionCharacter
的所有操作和属性都继承到您的Hero
类。
这也包括fight
操作。您将Hero
标记为实施CanFight
,但您继承了ActionCharacter
的实际实施。
答案 3 :(得分:0)
Hero需要实现void figth();
,但它会从ActionCharacter继承void figth();
,因此符合要求。
答案 4 :(得分:0)
接口只声明一个方法,不能在接口中定义方法。所以这意味着你要在界面中提供你想要实现的草稿。
现在,你的类Hero继承了ActionCharacter类,它有一个public void fight()的定义。但是,这个fight()与CanFight的fight()无关。所以如果你在Hero中定义一个fight(),你将覆盖ActionCharacter的fight()。
由于你也实现了CanFight接口,jvm将允许你在CanFight中声明方法,但它将被视为ActionCharacter的fight()的覆盖。