使用包含非导出参数类型的方法实现接口(Java 9 个模块)
Interface implementation with a method containing a non-exported parameter type (Java 9 modules)
我正在使用 Java 9 模块系统。下面是我的问题的简化版本。
我已经定义了 ClassA
(在模块 com.foo
中)来实现 InterfaceB
(在模块 com.bar
中)。 ClassA
实现了 InterfaceB
的方法 print
,它采用 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
模块不导出任何内容。因此,为了在编译 InterfaceB
和 ClassA
期间访问 ClassC
,我使用了 --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 包。我无法修改导出它的模块设置。)
我仍然不确定错误发生的原因或是否有意为之,但我确实找到了解决方案。
在编译 ClassA
时, 也 将 com.baz
模块导出到 com.bar
(InterfaceB
所在的位置)似乎允许编译器看到正确的 ClassC
class.
例如
-javac ... --add-exports com.baz/com.baz=com.foo,com.bar
虽然确实有办法让模块系统编译您的代码 (),但您会在 运行 时发现类似的问题,代码再次调用 InterfaceB::print
无法访问 ClassC
。同样,命令行标志可用于修复该问题。 但他们不应该这样做!
模块系统试图告诉你一些事情,在这里:"This modularization is broken!"
如果 com.baz
之外的 任何 模块应该被允许使用 ClassC
,那么包含它的包应该被导出!这正是出口的目的。其他代码显然依赖于 ClassC
并且构建模块系统是为了使这种依赖关系明确。因此,除非您在练习中这样做以了解命令行覆盖,否则真正的解决方案是 com.baz export com.baz
.
(如果不是所有模块都应该看到它,请考虑 qualified exports。如果涉及反射,其他方法可能更适合并且应该提出一个新问题。)
我正在使用 Java 9 模块系统。下面是我的问题的简化版本。
我已经定义了 ClassA
(在模块 com.foo
中)来实现 InterfaceB
(在模块 com.bar
中)。 ClassA
实现了 InterfaceB
的方法 print
,它采用 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
模块不导出任何内容。因此,为了在编译 InterfaceB
和 ClassA
期间访问 ClassC
,我使用了 --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 包。我无法修改导出它的模块设置。)
我仍然不确定错误发生的原因或是否有意为之,但我确实找到了解决方案。
在编译 ClassA
时, 也 将 com.baz
模块导出到 com.bar
(InterfaceB
所在的位置)似乎允许编译器看到正确的 ClassC
class.
例如
-javac ... --add-exports com.baz/com.baz=com.foo,com.bar
虽然确实有办法让模块系统编译您的代码 (InterfaceB::print
无法访问 ClassC
。同样,命令行标志可用于修复该问题。 但他们不应该这样做!
模块系统试图告诉你一些事情,在这里:"This modularization is broken!"
如果 com.baz
之外的 任何 模块应该被允许使用 ClassC
,那么包含它的包应该被导出!这正是出口的目的。其他代码显然依赖于 ClassC
并且构建模块系统是为了使这种依赖关系明确。因此,除非您在练习中这样做以了解命令行覆盖,否则真正的解决方案是 com.baz export com.baz
.
(如果不是所有模块都应该看到它,请考虑 qualified exports。如果涉及反射,其他方法可能更适合并且应该提出一个新问题。)