да, вы просто не можете защитить внутреннюю реализацию от доступа. Существуют некоторые технологии (такие как OSGi), которые предлагают решение для этого во время выполнения / запуска приложения. Это недостаток модульного дизайна языка Java (но также очень сложный для добавления из-за несовместимости).
Мне нравится соглашение о добавлении публично видимых артефактов в пакет / api и внутренних элементов в / internal . В конце концов вы получите.
# this package is allowed to be accessed by api-users
com.foo.users.api
# this is completely internal logic (api implementation)
# should only be touched by the api-module itself.
com.foo.users.internal
Таким образом, вы получаете чистое разделение, а также можете выполнять правила кода статического анализа кода.
Как и в случае с сервлет-api, упомянутым выше, вы можете еще больше разделить api и impl на разные банки. Но это требует больше усилий для сборки жизненного цикла и обслуживания модулей, поэтому я бы делал это только тогда, когда имеет смысл полное разделение артефактов во время выполнения (как в jsr-spec vs. impl).