默认访问权限是同包可见的轻量级栅栏,仅校验编译时包一致性,不区分源码路径或maven模块;运行时类加载器决定实际可见性,需配合语义化包名与设计意图使用。

默认访问权限(即不写任何修饰符)能让你在同包内自由组织类与成员的协作,但它不是“安全锁”,而是一道轻量级的可见性栅栏——它只管“能不能编译通过”,不管“谁在调用”或“是否合理”。真要靠它控制交互逻辑,得清楚边界在哪、怎么配合设计意图用。
默认权限只认运行时包,不认源码路径或 Maven 模块
很多人在多模块项目里把 com.example.service 放在 module-a,又把同名包复制到 module-b,以为设成 default 就天然隔离了。错。JVM 只看运行时加载进来的类是否属于同一个 runtime package:只要类加载器把两个同名包下的类都加进来了,它们就能互相访问 default 成员,哪怕物理路径完全不同、Maven 也完全独立。
- 模块未启用 JPMS(如没写
module-info.java或没用--module-path启动),default行为退化为传统 classloader 规则 - Maven 子模块若共用 classpath,且包名一致,
default成员对彼此完全透明 - IDE 编译时可能报“找不到符号”,但运行时一跑就通——因为 classpath 合并后包已“连通”
用 default 控制同包协作时,必须明确谁是“协作者”
默认权限本身不带语义,你得靠包结构和命名来传达意图。比如把一组强耦合的类全放进 com.example.order.internal,并让所有核心协调逻辑用 default 方法暴露,外部包只能通过 public 的 OrderService 入口调用——这时 default 才真正起到“限制交互面”的作用。
- 不要把
default成员散落在通用包(如com.example.common)里,否则等于开放给所有同包类,失去控制意义 - 包名建议带语义后缀:
xxx.api(只放public)、xxx.spi(public接口 +default回调钩子)、xxx.impl(大量default工具方法) - 如果某个类只该被包内特定几个类使用,别只靠
default,加个命名约定,比如以Internal结尾,再配 Javadoc 明确标注“仅限本包协作”
default 方法和字段容易被误当成“可继承”或“可反射突破”
default 方法不能被不同包的子类继承(除非是 protected),字段也不能靠反射绕过——反射访问 default 成员时,依然受包检查约束。但要注意:一旦类本身是 public,它的 default 成员在同包内对反射完全开放,没有额外防护。
-
Field.setAccessible(true)对同包内的default字段有效,无需特殊权限;跨包则抛IllegalAccessException - 子类即使在同一包,也不能直接继承父类的
default方法——继承关系不改变访问权限规则,子类仍需满足“同包”条件才能调用 - 避免在
default方法里做敏感判断(比如校验调用者身份),因为它无法区分是协作类还是临时测试类在调用
真正难的不是设成 default,而是让整个包的设计意图清晰、不可歧义。一旦包里混入职责不清的类,或出现“这个 default 方法我临时改下试试”的情况,那层可见性栅栏就形同虚设了。










