簡體   English   中英

當ECJ沒有時,為什么javac需要引用類的接口?

[英]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的新要求 - 如果不這樣做將導致編譯錯誤。


更新

  • 類似的問題: Java 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM