为什么JVM没有检测到丢失的方法实现?

时间:2015-09-08 13:54:40

标签: java

我们有一个应用程序,我们分别发布和接口和实现。用户将针对我们的界面进行编译,但只有在运行时才需要部署实现。实现永远不会明确提及。

如果你混合了界面版本和实现版本(例如新版本会添加方法),我会对将会发生什么感到好奇。所以,我做了一个简单的例子:

├── 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类包含某种接口实现。它的作用并不重要。 下一步是一点诡计。

  1. 我编译v1目录中的文件。
  2. 我将文件从v2复制到mix目录,以便我可以编译Mix.java
  3. 运行程序有效,无论是否设置属性“foo”。
  4. 我将DummyImpl.class从v1目录复制到mix目录。
  5. 我运行程序。它有效。
  6. v1实现显然不符合v2接口,但JVM很乐意允许我运行该程序。

    如果我设置“foo”属性,它将失败,但直到我实际到达代码中的那一行。

    我想这是我的问题所在:这是保证的行为吗?如果是这样,它在哪里指定了在这种情况下会发生什么/应该发生什么?

    我的例子当然是愚蠢的,但由于我们在一个更大的系统中有类似的情况,我想知道我们可以依靠什么工作,哪些不起作用以及我们无法知道它是什么?工作。

2 个答案:

答案 0 :(得分:4)

编译器为您的调用生成invokeinterface字节码(不是invokespecial)。此字节码对在运行时调用的具体方法执行多步查找。所以你的代码在编译时不会失败。

答案 1 :(得分:1)

因为您抽象了接口,所以客户端程序不知道运行的版本是v1。当它尝试调用v1中不存在的v2方法时,你最终会得到一个(不那么)好的NoSuchMethodError

提醒一下,Java中标记为错误的内容被认为是不可恢复的,您通常不应该尝试捕获它。