Java 8 接口/类加载器的变化?

4

我发现了Java 1.7_51和Java 1.8_20之间存在一些困难和谨慎。

最初的情况:

一个接口:

interface InterfaceA {
    public void doSomething();
}

两个类:

public class ClassA implements InterfaceA { 
    public void doSomething() {
        System.out.println("Hello World!");
    }
}

public class ClassB {
    public static void main(String[] args) {
        ClassA a = new ClassA();
        a.doSomething();
    }
}

接下来,我使用Java 1.8编译了这些类 -> javac *.java,在编译完成后,我删除了InterfaceA.java和InterfaceA.class文件。现在,我尝试再次编译只有ClassB.java,但是出现了错误消息:

ClassB.java:4: 错误: 无法访问InterfaceA a.doSomething();
找不到InterfaceA的类文件 1个错误

我也用Java 1.7尝试了同样的操作 -> javac *.java,在编译完成后,我删除了InterfaceA.java和InterfaceA.class文件,但是这次我没有收到任何错误消息..

有人能解释一下这是为什么吗?

..对不起我的英语不好..


通常情况下,该类将通过RMI重新加载。 - user2814648
2个回答

5
正式规范描述了查找调用表达式的目标方法的过程,首先搜索所有适用的方法,然后选择最具体的方法,如果没有歧义则成功。
参见 JLS 15.12.2.1. 确定可能适用的方法

由编译时步骤1(§15.12.1)确定的类或接口将搜索所有可能适用于此方法调用的成员方法;从超类和超接口继承的成员也包括在此搜索中。

在您的情况下,可以推断出在 ClassA 中找到的方法是一个确切的匹配项,编译器无法在 InterfaceA 中找到更具体的方法,但是规范并不要求编译器在此停止搜索,缩短搜索时间。这是编译器可能具有的一种优化,但是实现与正式指定完全相同的搜索,即首先搜索整个类型层次结构,然后再进行选择,是合适的。
鉴于所有新的Java 8功能和类型推断都非常微妙和复杂,当前的实现更保守而不是优化也就可以理解了。

3
我能想到两种可能的解释:
  1. 也许是Java 8中添加了默认方法、类型注释或其他内容,这意味着编译器需要更改以加载间接引用的接口的类文件。

  2. 也许这只是编译器重构的无害副作用。

不管怎样,在运行时并没有必要区分。在编译时的“修复”方法是不要像那样删除接口类文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接