为什么编译 public 泄漏内部类型的 API 不会失败?
Why does compilation of public APIs leaking internal types not fail?
我有以下 Java 9 模块:
module com.example.a {
exports com.example.a;
}
导出类型:
public class Api {
public static void foo(ImplDetail args) {}
}
还有一个非导出类型:
package com.example.b.internal;
public class ImplDetail {}
导出类型使用非导出类型作为public方法中的方法参数类型。我假设编译器会拒绝这种不一致的 class 配置,因为其他模块中的客户端无法真正调用 foo()
方法,因为它们无法实例化参数类型。
令我惊讶的是,这个模块被javac编译成功了。我可以看到传递 null
的特殊情况,但我仍然认为这样的 API 定义格式错误,并且认为它不应该被支持,理想情况下由编译器强制执行。
不禁止这种情况的原因是什么?
当然,在 API 中使用非导出类型是不好的风格,很可能是设计错误,但我很清楚 javac 无法做到这一点编译时错误。
请注意,一直可以在 public API 中使用私有类型,一直追溯到 Java 1.0.
您已经注意到模块外的代码仍然可以调用 Api.foo(null)
。
在其他情况下,调用者仍然可以将此 API 与非空引用一起使用。考虑包 com.example.a
中的 class public class Sub extends ImplDetail
。此 class Sub
是 public 并且已导出,因此可用于模块外的代码。因此,外部代码可以使用从某处获得的 Sub
实例调用 Api.foo(sub)
。
但是可以肯定的是,javac 可以判断任何导出的包中是否有任何 ImplDetail
的子类型,如果没有则发出编译时错误?不必要。由于单独编译的可能性,新的 classes 可能会在包含 Api
的编译步骤之后被引入到模块中。或者,就此而言,可以重新编译 module-info.class 文件以更改导出包的集合。
出于这些原因,我认为 javac 在编译 Api
class 时引发错误是不合适的。然而,Javac 确实有一个选项 -Xlint:exports
可以将此类情况标记为警告。
在构建过程的后期,例如 jmod 工具,或一些事后模块审计工具,也可以标记在导出中使用非导出类型的使用 API .不过,我认为目前没有任何东西可以做到这一点。
我有以下 Java 9 模块:
module com.example.a {
exports com.example.a;
}
导出类型:
public class Api {
public static void foo(ImplDetail args) {}
}
还有一个非导出类型:
package com.example.b.internal;
public class ImplDetail {}
导出类型使用非导出类型作为public方法中的方法参数类型。我假设编译器会拒绝这种不一致的 class 配置,因为其他模块中的客户端无法真正调用 foo()
方法,因为它们无法实例化参数类型。
令我惊讶的是,这个模块被javac编译成功了。我可以看到传递 null
的特殊情况,但我仍然认为这样的 API 定义格式错误,并且认为它不应该被支持,理想情况下由编译器强制执行。
不禁止这种情况的原因是什么?
当然,在 API 中使用非导出类型是不好的风格,很可能是设计错误,但我很清楚 javac 无法做到这一点编译时错误。
请注意,一直可以在 public API 中使用私有类型,一直追溯到 Java 1.0.
您已经注意到模块外的代码仍然可以调用 Api.foo(null)
。
在其他情况下,调用者仍然可以将此 API 与非空引用一起使用。考虑包 com.example.a
中的 class public class Sub extends ImplDetail
。此 class Sub
是 public 并且已导出,因此可用于模块外的代码。因此,外部代码可以使用从某处获得的 Sub
实例调用 Api.foo(sub)
。
但是可以肯定的是,javac 可以判断任何导出的包中是否有任何 ImplDetail
的子类型,如果没有则发出编译时错误?不必要。由于单独编译的可能性,新的 classes 可能会在包含 Api
的编译步骤之后被引入到模块中。或者,就此而言,可以重新编译 module-info.class 文件以更改导出包的集合。
出于这些原因,我认为 javac 在编译 Api
class 时引发错误是不合适的。然而,Javac 确实有一个选项 -Xlint:exports
可以将此类情况标记为警告。
在构建过程的后期,例如 jmod 工具,或一些事后模块审计工具,也可以标记在导出中使用非导出类型的使用 API .不过,我认为目前没有任何东西可以做到这一点。