3

我正在使用 Java 9 模块系统。以下是我的问题的简化版本。

我已经定义ClassA(在模块中com.foo)来实现InterfaceB(在模块中com.bar)。ClassA实现 的方法printInterfaceB它接受一个类型的参数ClassC(在模块中com.baz)。下面是代码。

// src/a/com/foo/ClassA.java
package com.foo;

import com.bar.InterfaceB;
import com.baz.ClassC;

public class ClassA implements InterfaceB {
    @Override
    public void print(ClassC obj) {
        System.out.println(obj);
    }
} 


// src/b/com/bar/InterfaceB.java
package com.bar;

import com.baz.ClassC;

public interface InterfaceB {
    public void print(ClassC obj);
}


// src/c/com/baz/ClassC.java
package com.baz;

public class ClassC {
    @Override
    public String toString() {
        return "This is a ClassC object";
    }
}

com.baz模块不导出任何内容。因此,为了在 and 的编译期间访问,ClassC我使用了标志。InterfaceBClassA--add-exports

InterfaceB成功编译,但是当我尝试编译时ClassA,我收到错误:

src/a/com/foo/ClassA.java:6: ClassA is not abstract and does not override abstract method print(ClassC) in InterfaceB

编译器是否以某种方式使用不同的实例ClassC?我有一种意料之外的事情正在发生--add-exports

(作为旁注,我使用的原因--add-exports是,在我的示例中,com.baz它实际上是一个内部 JDK 包。我无法修改模块设置来导出它。)

4

2 回答 2

4

虽然确实有一些方法可以让模块系统编译您的代码(您已经找到了),但您会在运行时发现类似的问题,再次,代码调用InterfaceB::print无法访问ClassC。同样,命令行标志可以用来解决这个问题。但他们不应该!

模块系统试图在这里告诉你一些事情:“这个模块化被破坏了!”

如果应该允许使用外部的任何模块,则应该导出包含它的包!这正是出口的目的。其他代码显然依赖于模块系统,并且构建模块系统以明确这些依赖关系。因此,除非您在练习中这样做以了解命令行覆盖,否则真正的解决方案是使用com.baz export 。com.bazClassCClassCcom.baz

(如果不是所有模块都应该看到它,请考虑合格的 exports。如果涉及反射,其他方法可能更适合,应该提出一个新问题。)

于 2016-12-02T09:16:24.797 回答
0

我仍然不确定为什么会发生错误或是否有意,但我确实找到了解决方案。

在编译ClassA时,com.baz将模块导出到com.bar(where InterfaceBis) 似乎允许编译器看到正确的ClassC类。

例如

-javac ... --add-exports com.baz/com.baz=com.foo,com.bar
于 2016-12-02T03:08:00.890 回答