当编译一个Client (它使用了一些接口I的实现(例如O) )时,I的类文件也必须出现在类路径上。奇怪的是,这只是javac的一个例子,因为Eclipse编译器(ECJ)在编译时不需要I。
是什么使JDK需要编译的超级类型,其中ECJ编译得很好?
正如注释在错误报告中那样,它不是默认方法,兼容性指南也同意:
当针对实现另一个类文件中定义的接口的另一个类编译一个类时,这个类文件(其中定义了接口)必须在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();
}
}一个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发布于 2017-07-11 10:06:21
发布于 2017-07-11 09:18:49
如果O不覆盖doit()怎么办?
那么Client必须仍然能够调用doit(),因为它是I合同的一部分,但是O的类文件中缺少这个信息。
您可能会问:“为什么不在O的类文件中包含默认的方法定义?”,这将打破引入默认方法的初衷:使用预Java-8编译器编译的类仍然可以在Java8中工作,并且应该有新的接口。
https://stackoverflow.com/questions/45030100
复制相似问题