访问控制(或隐藏具体实现)与"最初的实现并不恰当"有关。
一、访问控制基础理论
1.1 访问控制的核心目的
封装性:隐藏对象内部实现细节
安全性:防止外部代码意外破坏对象状态
模块化:明确组件边界和交互接口
可维护性:减少耦合,便于修改内部实现
1.2 Java访问权限层级体系
访问级别 | 关键字 | 可见范围 |
---|---|---|
公开访问 | public | 所有类 |
包级私有 | (默认) | 同一包内 |
受保护 | protected | 同一包内+子类 |
私有访问 | private | 仅当前类 |

二、类成员访问权限详解
2.1 public访问权限
2.1.1 特性分析
最大可见性:可被任何其他类访问
API设计:构成类的外部契约
使用建议:
public class BankAccount { public BigDecimal getBalance() { ... } // 公共API方法 public void deposit(BigDecimal amount) { ... } }
2.1.2 典型应用场景
对外暴露的服务接口
常量定义(通常配合static final)
工具类方法
2.2 protected访问权限
2.2.1 跨包继承可见性
// Package A
public class Parent {
protected int protectedField;
}
// Package B
public class Child extends Parent {
void method() {
protectedField = 10; // 可访问父类protected成员
}
}
// Package B
public class Unrelated {
void method() {
Parent p = new Parent();
// p.protectedField = 10; // 编译错误!非子类不能访问
}
}
2.2.2 设计考量
继承框架:允许子类访问但限制外部使用
封装平衡:比包访问更开放,比public更受限
最佳实践:
public abstract class Shape { protected abstract void drawInternal(); // 子类实现细节 public final void draw() { preDraw(); drawInternal(); postDraw(); } }
2.3 默认(package-private)访问权限
2.3.1 包内协作机制
// Package com.example.util
class PackagePrivateHelper { // 默认访问权限
void doWork() { ... }
}
public class PublicTool {
PackagePrivateHelper helper = new PackagePrivateHelper();
public void service() {
helper.doWork(); // 同一包内可访问
}
}
2.3.2 设计模式应用
工厂模式:隐藏实现类
包私有实现:仅暴露必要接口
测试友好:同一包内的测试类可访问
2.4 private访问权限
2.4.1 严格封装实现
public class StrictEncapsulation {
private int secretValue;
private void internalProcess() { ... }
public void publicMethod() {
internalProcess(); // 仅内部可调用
}
}
2.4.2 现代Java增强
Record类:自动生成private final字段
密封类:配合private实现更严格继承控制
三、类本身访问控制
3.1 public类规范
3.1.1 文件命名要求
每个.java文件只能有一个public类
文件名必须与public类名完全一致
可以有多个非public类(但非推荐做法)
3.1.2 跨项目可见性
projectA/src/com/example/PublicClass.java
projectB/src/.../Client.java
// Client.java可以:
import com.example.PublicClass;
3.2 默认访问权限类
3.2.1 包内专用类
// Package com.example.internal
class InternalUtils { // 默认访问权限
static void helperMethod() { ... }
}
// 同一包内的其他类可访问
public class Service {
void service() {
InternalUtils.helperMethod();
}
}
3.2.2 设计优势
模块化封装:隐藏非必要公开的实现类
减少API污染:避免外部代码依赖内部实现
四、接口与枚举的访问控制
4.1 接口成员访问规则
4.1.1 默认public特性
public interface MyInterface {
int CONSTANT = 10; // 默认public static final
void method(); // 默认public abstract
}
4.1.2 Java 9+私有方法
public interface ModernInterface {
private void internalHelper() { ... } // Java 9+
default void service() {
internalHelper();
}
}
4.2 枚举类型访问控制
4.2.1 枚举常量特性
public enum Color {
RED, GREEN, BLUE; // 默认public static final
private int code; // 枚举私有字段
public int getCode() { return code; }
}
4.2.2 包私有枚举应用
enum InternalState { // 包内可见
INIT, WORKING, DONE
}
五、模块系统下的访问控制(Java 9+)
5.1 module-info.java规范
module com.example.myapp {
requires java.base;
requires transitive com.example.common;
exports com.example.api;
opens com.example.internal to com.example.test;
}
5.2 模块访问权限类型
指令 | 作用 | 示例 |
---|---|---|
exports | 导出包 | exports com.example.api |
opens | 反射开放 | opens com.example.internal |
requires | 模块依赖 | requires java.sql |
provides...with | 服务提供 | provides Service with MyServiceImpl |
六、设计模式中的访问控制应用
6.1 工厂方法模式
public interface Product {
void use();
}
class ConcreteProduct implements Product { // 包私有实现
@Override
public void use() { ... }
}
public class ProductFactory {
public static Product getProduct() {
return new ConcreteProduct(); // 包内可访问
}
}
6.2 单例模式实现
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {} // 私有构造器
public static Singleton getInstance() {
return INSTANCE;
}
}
七、访问控制最佳实践
7.1 成员访问设计原则
最小权限原则:从private开始,按需放宽
稳定接口:public方法应保持长期兼容
防御性编程:protected成员也应考虑子类误用
文档配套:明确说明protected/包私有成员的预期用途
7.2 典型设计模板
public class WellDesignedClass {
// 1. 私有字段
private int internalState;
// 2. 包私有构造器(工厂方法模式)
WellDesignedClass(int initialState) {
this.internalState = initialState;
}
// 3. 公共API方法
public void publicMethod() {
internalHelper();
}
// 4. 受保护的可扩展点
protected void overrideMe() { ... }
// 5. 包私有工具方法
void packagePrivateUtility() { ... }
// 6. 私有实现细节
private void internalHelper() { ... }
}
八、常见问题与解决方案
8.1 反射绕过访问限制
问题表现
Field f = obj.getClass().getDeclaredField("privateField");
f.setAccessible(true); // 绕过private限制
f.set(obj, value);
防御方案
Java 9+模块系统限制非法访问
安全管理器检查
关键字段使用SecurityManager验证
8.2 跨包继承问题
典型场景
// Package A
public class Base {
protected int value;
}
// Package B
public class Derived extends Base {
void method() {
Base b = new Base();
// b.value = 10; // 编译错误!必须通过Derived实例访问
this.value = 10; // 正确
}
}
解决方案
通过protected方法而非直接字段访问
使用包结构合理规划继承体系
**结语:**随着Java语言的演进,访问控制在模块化、安全性等方面持续增强,成为Java编程中不可或缺的核心概念。