编译使用接口Client
的某些实现的I
时(例如O
),类I
的类文件也必须存在于类路径中。奇怪的是,这只是javac
的一种情况,因为Eclipse编译器(ECJ)不需要I
进行编译。
是什么让JDK 需要超类型进行编译,其中ECJ编译得很好?
这不是默认方法,如评论in the bug report,compatibility guide也同意:
当针对另一个实现在另一个类文件中定义的接口的类编译类时,这样的类文件(其中定义了接口)必须在编译期间由javac使用的类路径中可用。这是JDK 8的新要求 - 如果不这样做将导致编译错误。
更新:
I.doit()
是default
或简单的抽象方法无关紧要,行为是相同的I.doit()
是否覆盖了O
,这当然很重要;如果没有覆盖,那么ECJ也会到达I
以获得doit()
界面(api/a/I.java
):
package a;
public interface I {
default void doit() {
System.out.println("In I");
}
}
实施(impl/b/O.java
):
package b;
public class O implements a.I {
public void doit() {
System.out.println("In O");
}
}
客户(client/c/Client.java
):
package c;
import b.O;
public class Client {
public void test() {
O o = new O();
o.doit();
}
public static void main(String[] args) {
new Client().test();
}
}
A Makefile
:
# bug report:
# Javac requires interface on classpath when using impl
# https://bugs.openjdk.java.net/browse/JDK-8055048
#
# compatibility guide:
# http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html
# (Synopsis: Interfaces need to be present when compiling against their implementations)
#
# ECJ downloaded from:
# http://central.maven.org/maven2/org/eclipse/jdt/core/compiler/ecj/4.6.1/ecj-4.6.1.jar
ifeq (${V}, ecj)
JC := java -jar ecj-4.6.1.jar -8
else
JC := javac -source 1.8 -target 1.8 -implicit:none
endif
rebuild: clean lib client
lib: api/a/I.class impl/b/O.class
client: lib client/c/Client.class
clean:
rm -f api/a/I.class impl/b/O.class client/c/Client.class
%.class: %.java
${JC} ${OPT} $<
impl/b/O.class: OPT = -cp api
client/c/Client.class: OPT = -cp impl
日志:
$ make V=ecj rebuild
rm -f api/a/I.class impl/b/O.class client/c/Client.class
java -jar ecj-4.6.1.jar -8 api/a/I.java
java -jar ecj-4.6.1.jar -8 -cp api impl/b/O.java
java -jar ecj-4.6.1.jar -8 -cp impl client/c/Client.java
$ make rebuild
rm -f api/a/I.class impl/b/O.class client/c/Client.class
javac -source 1.8 -target 1.8 -implicit:none api/a/I.java
javac -source 1.8 -target 1.8 -implicit:none -cp api impl/b/O.java
javac -source 1.8 -target 1.8 -implicit:none -cp impl client/c/Client.java
client/c/Client.java:8: error: cannot access I
o.doit();
^
class file for a.I not found
1 error
make: *** [client/c/Client.class] Error 1
答案 0 :(得分:6)
似乎对Compatibility Guide for JDK 8的目的存在误解。
这不是关于编译器或环境应该如何行为的规范,它是关于JDK 如何行为的文档,以发现潜在的兼容性问题。这并不意味着另一个编译器必须表现出完全相同的行为。
它提到特定行为的原因是,因为javac
将其行为从JDK 7更改为JDK 8,这可能会导致兼容性问题。
正如here所解释的那样,正式过程被描述为搜索方法调用的所有可能适用的成员方法,但它并没有说当程序的正确性时,不允许使用快捷方式。保证。
所以that bug report已经关闭,因为新行为在规范范围内,不一定是因为替代行为会违反它。
答案 1 :(得分:3)
如果O
未覆盖doit()
,该怎么办?
然后Client
必须仍然可以致电doit()
,因为它是I
合同的一部分,但O
中缺少此信息}&#39;类文件。
您可能会问&#34;为什么不在O
的类文件中包含默认方法定义?&#34;。这将首先打破引入默认方法的意图:使用Java-8之前的编译器编译的类仍应在Java 8中工作,并且接口新方法应该可用。