Ответ 1
Конечно, использование неэкспортированного типа в API - это плохой стиль и, скорее всего, будет ошибкой дизайна, но мне совершенно ясно, что javac не в состоянии сделать это ошибкой времени компиляции.
Обратите внимание, что всегда можно было использовать закрытый тип в общедоступном API, полностью возвращаясь к Java 1.0.
Вы уже отметили, что код вне модуля все равно может вызвать Api.foo(null)
.
Существуют и другие случаи, когда вызывающий может использовать этот API с ненулевой ссылкой. Рассмотрим класс public class Sub extends ImplDetail
в пакете com.example.a
. Этот класс Sub
является общедоступным и экспортируется и поэтому доступен для кода вне модуля. Таким образом, внешний код может вызывать Api.foo(sub)
, используя экземпляры Sub
, полученные откуда-то.
Но, конечно, javac может определить, есть ли какие-либо подтипы ImplDetail
в любых экспортированных пакетах и выдавать ошибку времени компиляции, если их нет? Не обязательно. Из-за возможности отдельной компиляции новые классы могут быть введены в модуль после этапа компиляции, который включает Api
. Или, если на то пошло, файл module-info.class можно перекомпилировать для изменения набора экспортированных пакетов.
По этим причинам я считаю неприемлемым для javac для повышения ошибки в момент компиляции класса Api
. Однако у Javac есть опция -Xlint:exports
, которая будет отмечать такие случаи как предупреждение.
Что-то позже в процессе сборки, например, в инструменте jmod или в каком-то дополнительном модуле аудита модулей, можно также указать использование неэкспортируемого типа, используемого в экспортированном API. Я не думаю, что сейчас что-то делает.