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

结合场景再看三个关注点

  1. public 类型才是跨包 API 候选
  2. 包私有实现类减少外部依赖面。
  3. private 字段防止外部破坏不变量。

核心概念与准确模型

1. 修饰符(成员)

修饰符同类同包子类(异包)世界
private
包私有(默认)
protected
public

2. 类型可见性

  • 顶层类型:public 或包私有
  • 一个编译单元至多一个 public 顶层类型

3. 导出 Impulses

  • 模块系统用 exports 再收紧(见模块篇)

边界情况与反直觉行为

  1. protected 成员可被子类访问,也同包可访问。
  2. 测试若异包,需 public/测试专用钩子。
  3. 反射可绕过,但不是常规 API。

常见误区

[!warning] 常见误区:所有类全部 public 扩大耦合与破坏面;默认应最小可见。

工程实践

  1. 先 private,必要时再放宽。
  2. API 与 impl 分包(..api / ..internal)。
  3. 避免 protected 字段,优先 protected 方法。
  4. 与 JPMS 联用进一步隐藏。

本节总结

  • 包=命名空间;修饰符=边界
  • 最小可见性
  • 为模块与分层铺路

自测题

  1. 无修饰符的类成员谁可见?
  2. 为什么字段优先 private?
参考答案
  1. 同包可见(包私有)。
  2. 隐藏表示,强制经方法维护不变量。

延伸阅读与资料来源

资料类型支撑内容
Controlling Access教程访问控制
JLS Access Control规范可见性
创建于 2026/7/15 更新于 2026/7/15