在Java和类似语言中,必须明确表示类实现接口的真正原因是什么?
想象一下隐式实现:
interface Flyer { void fly(); }
public class Duck { public void fly() {...} }
public class Plane { public void fly() {...} }
public class Hoe { void hangAround() {...} }
void startFlying(Flyer flyer) {...}
void race() {
...
startFlying(duck); // OK
startFlying(plane); // OK
startFlying(hoe); // Compilation error.
}
编译器知道方法的签名,返回类型(当然还有修饰符)。此时似乎很清楚,没有必要明确指定Duck和Plane实现Flyer。
我会说可以从Java中删除“实现XYZ”而不用担心。
没有区别,请在编译时检查,这样就可以了。
另一方面: @JBNizet提到了具有相同签名和返回类型的方法的不同含义。
我将使用他的例子:
interface Runner { void run(); }
public class Guy { public void run(); }
public class Gal { public void run(); }
void startRunning(Runner r) {...}
void race() {
startRunning(guy); // OK
startRunning(gal); // OK
startRunning(runnableThread); // OK
}
确定编译器,确定startRunning()(对我来说没问题)。如果这对你好或没有,那取决于你的理念。
显式:
public class Guy **implements Runner **{ public void run(); }
public class Gal **implements Runner **{ public void run(); }
以粗体显示(或**和**之间的文字)是您必须支付的价格
void race() {
startRunning(guy); // OK
startRunning(gal); // OK
startRunning(runnableThread); // Compilation error!
}
请注意编译错误,以便在测试之前查看问题。
如果它打算在startRunning()中使用runnableThread,你必须更明确地做到这一点(有足够的时间来实现你正在做的事情)。
“我想知道通过解决与隐式实现的接口问题浪费的时间相比,通过解决与键入”implements XYZ“相关的问题浪费了多少时间。如果对隐式实现的接口更好,那么我讨厌Java设计师决定,他们迫使我们相信它更好:-)“
瓢虫和空中客车(和鸭子)
我认为隐式实现界面的问题只是理论上的,实际上很少见。
public class Airbus {
void takeOff() {...}
void land() {...}
Passenger[] getPassengers() {...}
}
public class Ladybug {
void takeOff() {...}
void land() {...}
}
public class Duck {
void takeOff() {...}
void land() {...}
Passenger[] getPassengers() {...}
}
public interface Aircraft {
void takeOff();
void land();
Passenger[] getPassengers();
}
public void fly(Aircraft aircraft) {
aircraft.takeOff();
for (Passenger p : aircraft.getPassengers()) {...}
aircraft.land();
}
public void airport() {
fly(airbus_a380); // OK
fly(ladybug); // Compilation error, does not match Aircraft requirements.
fly(duck); // OK
}
public interface Lander {
void land();
}
public void landAtMeadow(Lander lander) {...}
public void meadow() {
landAtMeadow(airbus_a380); // OK
landAtMeadow(duck); // OK
landAtMeadow(ladybug); // OK
}
所有这些都符合landAtMeadow的要求,因此可以在这种情况下使用它们。即使有可能无法在草地上降落airbus_a380(在其他方面需要测试),你需要在紧急情况下降落。
不要忘记landAtMeadow()可能有更具体的要求,如
public interface Lander { void landAtLimitedArea(int size); }
说空间有限,所以如果airbus_a380不支持这种方法,那么你在这里有编译错误。
答案 0 :(得分:5)
Java是一种强类型语言,因此必须在编译时验证实例到接口类型变量的分配。这只能通过显式声明的接口实现来完成。
答案 1 :(得分:1)
正如其他人所说,这是Java语言的基本特征。这是有充分理由的,那些正在进行严肃的大规模编程的人,并且完全没有理由改变它。
如果它困扰你,我强烈建议您找到另一种类型较弱的语言并使用它。目前有相当多的语言可以编译成Java字节码并在Java环境中使用,因此您甚至不必放弃能够在JVM中运行的灵活性。
答案 2 :(得分:0)
我的朋友在强类型语言中,例如:在C或Java中,当声明变量或引用时,必须通知编译器变量或引用的数据类型
答案 3 :(得分:0)
当声明一个类实现接口X时,使用接口X 的任何其他方法都确保所有必要的方法都在类中实现(因此它们不需要每个都检查时间,如果需要的方法实施)。如果没有这样的声明,那么使用实现X的类的任何方法都需要:
确保该方法正在工作的对象类实现了所有必要的方法(因此,每次期望使用接口X时,请仔细检查类的所有方法 - 而不是执行这一次,在汇编时。)
有很多错误处理代码行实现(怎么做,如果我希望方法A做某事,但方法A根本不存在?)
静态类型通常会增加代码的安全性,因为在编译时可能会检测到许多错误。为什么要尝试将Java从staticaly更改为dynamicaly类型?有许多动态类型的语言,它们的优点和缺点,随时可用(例如Python)。