我们有一个应用程序,我们分别发布和接口和实现。用户将针对我们的界面进行编译,但只有在运行时才需要部署实现。实现永远不会明确提及。
如果你混合了界面版本和实现版本(例如新版本会添加方法),我会对将会发生什么感到好奇。所以,我做了一个简单的例子:
├── mix
│ └── Mix.java
├── v1
│ ├── DummyImpl.java
│ └── DummyInterface.java
└── v2
├── DummyImpl.java
└── DummyInterface.java
接口的v1如下所示:
interface DummyInterface {
void v1();
}
接口的v2如下所示:
interface DummyInterface {
void v1();
void v2();
}
Mix.java文件如下所示:
class Mix {
public static void main(String[] args) {
DummyInterface di = new DummyImpl();
di.v1();
if (System.getProperty("foo") != null)
di.v2();
}
}
* Impl类包含某种接口实现。它的作用并不重要。 下一步是一点诡计。
v1实现显然不符合v2接口,但JVM很乐意允许我运行该程序。
如果我设置“foo”属性,它将失败,但直到我实际到达代码中的那一行。
我想这是我的问题所在:这是保证的行为吗?如果是这样,它在哪里指定了在这种情况下会发生什么/应该发生什么?
我的例子当然是愚蠢的,但由于我们在一个更大的系统中有类似的情况,我想知道我们可以依靠什么工作,哪些不起作用以及我们无法知道它是什么?工作。
答案 0 :(得分:4)
编译器为您的调用生成invokeinterface
字节码(不是invokespecial
)。此字节码对在运行时调用的具体方法执行多步查找。所以你的代码在编译时不会失败。
答案 1 :(得分:1)
因为您抽象了接口,所以客户端程序不知道运行的版本是v1。当它尝试调用v1中不存在的v2方法时,你最终会得到一个(不那么)好的NoSuchMethodError
。
提醒一下,Java中标记为错误的内容被认为是不可恢复的,您通常不应该尝试捕获它。