← [ BACK_TO_NOTES ]

Java 包与可见性

package 组织与 public/protected/包私有/private 可见性如何约束 API 边界。

#concept #growing #dev #java

[!info] related notes

Java 包与可见性

这个概念为什么出现

大型代码库靠边界生存:哪些类型对外,哪些是内部细节。Java 用包名组织命名空间,用访问修饰符控制成员与类型可见性。

[!abstract] 一句话理解 package 定义命名空间与目录约定;访问修饰符按声明位置、所在包和继承关系控制谁能访问类型与成员,是 API 设计的第一道墙。

最小可运行示例

场景:订单模块对外只暴露服务,仓储实现包内可见

// 保存为 shop/order/OrderService.java
package shop.order;

public class OrderService {
    private final OrderRepository repo = new OrderRepository();
    public String place(String sku) {
        return repo.save(sku);
    }
}

// 包私有:包外不能直接引用此类型(即使仍在同一模块)
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 或包私有
  • javac 的文件编译约定要求 public 顶层类型名与文件名一致,因此一个 .java 文件至多有一个;嵌套类型另有可见性规则。

3. 模块导出

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

边界情况与反直觉行为

  1. 跨包访问 protected 实例成员必须发生在子类实现中;通过引用访问时,接收者静态类型须为该子类或其子类型,不能任取父类对象。同包访问不受此子类接收者限制。
  2. private 成员可被同一顶层类型内的嵌套类型访问;子包与父包是不同包,没有额外包私有权限。
  3. 表格以可访问的声明类型为前提;模块导出和读取关系仍可限制 public 访问。反射也受到模块封装,不能任意绕过。

常见误区

[!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/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本