![](/img/trans.png)
[英]Does javac generate inaccurate line numbers compared to ecj (for this particular case)?
[英]Why javac requires an interfaces of referenced classes when ECJ does not?
當編譯一個Client
,它使用執行界面I
(例如O
),為類文件I
也必須存在於類路徑。 奇怪的是,這只是javac
一個案例,因為Eclipse編譯器(ECJ)不需要I
進行編譯。
是什么讓JDK 需要超類型進行編譯,ECJ編譯得很好?
它不是默認方法,如錯誤報告中所評論的那樣 , 兼容性指南也同意:
在針對另一個實現在另一個類文件中定義的接口的類編譯類時,這樣的類文件(其中定義了接口)必須在編譯期間由javac使用的類路徑中可用。 這是JDK 8的新要求 - 如果不這樣做將導致編譯錯誤。
更新 :
I.doit()
是default
或簡單的抽象方法,則行為是相同的 O
覆蓋了I.doit()
它I.doit()
重要; 如果沒有覆蓋,那么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
似乎對JDK 8兼容性指南的目的存在誤解。
這不是一個關於編譯器或環境中應該如何行為規范,這是一個關於JDK 不如何表現,發現潛在兼容性問題的文件。 這並不意味着另一個編譯器必須表現出完全相同的行為。
它之所以提到特定行為,是因為javac
將其行為從JDK 7改為JDK 8,這可能會導致兼容性問題。
正如這里所解釋的那樣,正式過程被描述為搜索方法調用的所有可能適用的成員方法,但是並不表示當可以保證程序的正確性時不允許快捷方式。
因此bug報告已經關閉,因為新行為在規范范圍內,不一定是因為替代行為會違反它。
如果O
不覆蓋doit()
怎么辦?
然后Client
仍然可以調用doit()
因為它是I
的合同的一部分,但是O
的類文件中缺少這個信息。
您可能會問“為什么不在O
的類文件中包含default-methods定義?”。 這將首先打破引入默認方法的意圖:使用Java-8之前的編譯器編譯的類仍應在Java 8中工作,並且接口新方法應該可用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.