首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么javac需要引用类的接口,而ECJ不需要?

为什么javac需要引用类的接口,而ECJ不需要?
EN

Stack Overflow用户
提问于 2017-07-11 09:08:45
回答 2查看 620关注 0票数 2

当编译一个Client (它使用了一些接口I的实现(例如O) )时,I的类文件也必须出现在类路径上。奇怪的是,这只是javac的一个例子,因为Eclipse编译器(ECJ)在编译时不需要I

是什么使JDK需要编译的超级类型,其中ECJ编译得很好?

正如注释在错误报告中那样,它不是默认方法,兼容性指南也同意:

当针对实现另一个类文件中定义的接口的另一个类编译一个类时,这个类文件(其中定义了接口)必须在javac编译期间使用的类路径中可用。这是JDK 8中的一个新要求--如果不这样做,将导致编译错误。

更新

  • 类似问题:Java 8接口/类加载器更改?
  • 不管I.doit()default还是普通的抽象方法,行为都是一样的
  • 当然,I.doit()是否在O中被覆盖是很重要的;如果不被覆盖,那么ECJ也会达到I来定义doit()

接口(api/a/I.java):

代码语言:javascript
复制
package a;
public interface I {
    default void doit() {
        System.out.println("In I");
    }
}

实现(impl/b/O.java):

代码语言:javascript
复制
package b;
public class O implements a.I {
    public void doit() {
        System.out.println("In O");
    }
}

客户端(client/c/Client.java):

代码语言:javascript
复制
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

代码语言:javascript
复制
# 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

原木:

代码语言:javascript
复制
$ 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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-11 10:06:21

JDK 8兼容性指南的目的似乎存在误解。

这不是关于编译器或环境应该如何运行的规范,而是关于JDK行为的文档,以发现潜在的兼容性问题。这并不意味着另一个编译器必须表现出完全相同的行为。

它之所以提到这个特定的行为,是因为javac将其行为从JDK 7更改为JDK 8,这可能会导致兼容性问题。

正如解释的这里所描述的那样,形式过程被描述为为方法调用搜索所有可能适用的成员方法,但它并不表示当程序的正确性得到保证时,不允许使用捷径。

因此,那个错误报告已经关闭,因为新的行为在规范中,而不一定是因为替代行为会违反它。

票数 6
EN

Stack Overflow用户

发布于 2017-07-11 09:18:49

如果O不覆盖doit()怎么办?

那么Client必须仍然能够调用doit(),因为它是I合同的一部分,但是O的类文件中缺少这个信息。

您可能会问:“为什么不在O的类文件中包含默认的方法定义?”,这将打破引入默认方法的初衷:使用预Java-8编译器编译的类仍然可以在Java8中工作,并且应该有新的接口。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45030100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档