Java 包与可见性
package 组织与 public/protected/包私有/private 可见性如何约束 API 边界。
#type / concept
#status / growing
#tech / dev
#resource / java
[!info] 关联笔记
Java 包与可见性
这个概念为什么出现
大型代码库靠边界生存:哪些类型对外,哪些是内部细节。Java 用包名组织命名空间,用访问修饰符控制成员与类型可见性。
[!abstract] 一句话理解
package定义命名空间与目录约定;private < 包私有 < protected < public控制谁能访问类型与成员,是 API 设计的第一道墙。
最小可运行示例
场景:订单模块对外只暴露服务,仓储实现包内可见
// 文件概念示例:同一包 shop.order 内
package shop.order;
public class OrderService {
private final OrderRepository repo = new OrderRepository();
public String place(String sku) {
return repo.save(sku);
}
}
// 包私有:模块外不能直接 new
class OrderRepository {
String save(String sku) { return "saved-" + sku; }
}
// 演示入口可放同包或测试
class OrderServiceDemo {
public static void main(String[] args) {
System.out.println(new OrderService().place("S1"));
}
}
建议运行(需按包目录放置后编译):
# 在源码根目录
javac shop/order/*.java && java shop.order.OrderServiceDemo
期望输出:
saved-S1
结合场景再看三个关注点
- public 类型才是跨包 API 候选。
- 包私有实现类减少外部依赖面。
- private 字段防止外部破坏不变量。
核心概念与准确模型
1. 修饰符(成员)
| 修饰符 | 同类 | 同包 | 子类(异包) | 世界 |
|---|---|---|---|---|
| private | ✓ | |||
| 包私有(默认) | ✓ | ✓ | ||
| protected | ✓ | ✓ | ✓ | |
| public | ✓ | ✓ | ✓ | ✓ |
2. 类型可见性
- 顶层类型:public 或包私有
- 一个编译单元至多一个 public 顶层类型
3. 导出 Impulses
- 模块系统用
exports再收紧(见模块篇)
边界情况与反直觉行为
- protected 成员可被子类访问,也同包可访问。
- 测试若异包,需 public/测试专用钩子。
- 反射可绕过,但不是常规 API。
常见误区
[!warning] 常见误区:所有类全部 public 扩大耦合与破坏面;默认应最小可见。
工程实践
- 先 private,必要时再放宽。
- API 与 impl 分包(
..api/..internal)。 - 避免 protected 字段,优先 protected 方法。
- 与 JPMS 联用进一步隐藏。
本节总结
- 包=命名空间;修饰符=边界
- 最小可见性
- 为模块与分层铺路
自测题
- 无修饰符的类成员谁可见?
- 为什么字段优先 private?
参考答案
- 同包可见(包私有)。
- 隐藏表示,强制经方法维护不变量。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Controlling Access | 教程 | 访问控制 |
| JLS Access Control | 规范 | 可见性 |