pwe*_*wes 2 java javac java-8 ecj
在编译a时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");
}
}
Run Code Online (Sandbox Code Playgroud)
实施(impl/b/O.java):
package b;
public class O implements a.I {
public void doit() {
System.out.println("In O");
}
}
Run Code Online (Sandbox Code Playgroud)
客户(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();
}
}
Run Code Online (Sandbox Code Playgroud)
答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
Run Code Online (Sandbox Code Playgroud)
一个日志:
$ 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
Run Code Online (Sandbox Code Playgroud)
似乎对JDK 8兼容性指南的目的存在误解.
这不是一个关于编译器或环境如何规范应该的行为,这是一个关于JDK文档如何不循规蹈矩,以发现潜在的兼容性问题.这并不意味着另一个编译器必须表现出完全相同的行为.
它之所以提到特定行为,是因为javac它将其行为从JDK 7改为JDK 8,这可能会导致兼容性问题.
正如这里所解释的那样,正式过程被描述为搜索方法调用的所有可能适用的成员方法,但是并不表示当可以保证程序的正确性时不允许快捷方式.
因此bug报告已经关闭,因为新行为在规范范围内,不一定是因为替代行为会违反它.