最直接有效的测试方式是用「跨包+继承+对象调用」三要素构造边界用例:p1中Parent定义protected doWork(),p2中子类可直接调用但不可通过new Parent()调用;default方法在p1内可访问、p2中无论子类与否均不可见;且子类重写protected方法时权限不得低于protected。

最直接有效的测试方式,是用「跨包 + 继承 + 对象调用」三要素组合构造边界用例,重点验证 protected 和 default 的行为差异。public 和 private 的边界相对明确,容易出错的恰恰是那两个“看起来能用、实际受限”的情况。
构造最小跨包结构验证 protected
新建两个包:p1 和 p2。在 p1 中定义父类:
package p1;
public class Parent {
protected void doWork() {}
}
在 p2 中写子类和非子类两类测试:
-
子类内部调用(应成功):继承
Parent,直接调用doWork()—— 编译通过,说明继承链下 protected 可见 -
非子类调用对象方法(应失败):在
p2新建Other类,写new Parent().doWork()—— 编译报错,证明跨包非子类不可通过点号访问 -
子类对象被同包类调用(易忽略!应失败):若
C2 extends Parent在p2,再建C3在p2并调用new C2().doWork()—— 仍报错,因为doWork()最初定义在p1,而C3与p1不同包
用同包/跨包对比验证 default(无修饰符)
把 Parent 中的 doWork() 改成不加任何修饰符:
立即学习“Java免费学习笔记(深入)”;
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 在
p1内新建Helper类调用new Parent().doWork()—— 成功 - 在
p2中同样调用 —— 编译失败,确认 default 确实只限本包 - 注意:即使
p2有子类继承Parent,该子类也无法在自己体内调用doWork()(因未继承 default 成员),这是和 protected 的关键区别
检查子类重写时的权限收缩陷阱
在 p1 中定义:
public class Base {
protected void run() {}
}
在 p2 中子类尝试不同修饰符重写:
-
public void run()—— 合法,权限放宽允许 -
void run()(default)—— 编译失败,权限不能比父类更严格 -
private void run()—— 同样失败,private 无法覆盖 protected
这类错误常在重构或 IDE 自动生成重写时悄悄出现,必须显式编译验证。
真实调用链测试(不止看编译)
光过编译不够,还要模拟运行时典型场景:
- 用 JUnit 写测试类(通常在
test包),调用目标类的 public 方法,观察其内部是否正确使用了 private 辅助方法 —— 验证封装没被破坏 - 在 Spring Boot 项目中,把
@PostConstruct方法设为 private,启动应用 —— 应抛IllegalStateException,确认框架反射调用受权限约束 - 把工具类核心方法设为 default,从另一个模块(不同 Maven module / 不同包)调用 —— 编译失败,验证模块边界生效

















