1. 概述

本文深入探讨 Java 中的访问修饰符(Access Modifiers),它们用于控制类、变量、方法和构造器的访问级别。

✅ 简单来说,Java 提供了四种访问修饰符:publicprivateprotected 和默认(即不写任何关键字,也叫 package-private)。

⚠️ 需要注意的是:顶层类只能使用 public 或默认访问修饰符;而类的成员(字段、方法等)则可以使用全部四种。

合理使用访问修饰符是实现封装、提升代码安全性和可维护性的关键。踩过坑的人都知道,随便用 public 会导致类的内部细节暴露过多,后期重构寸步难行。


2. 默认访问修饰符(default / package-private)

当你没有显式指定任何访问修饰符时,Java 会自动赋予该成员“默认”访问权限,也称为 包私有(package-private)

这意味着:

  • ✅ 同一个包内的其他类可以访问该成员
  • ❌ 不同包的类无法访问

示例代码如下:

package com.example.access;

public class SuperPublic {
    static void defaultMethod() {
        System.out.println("This is package-private method");
    }
}

在同一个包中可以正常调用:

package com.example.access;

public class Public {
    public Public() {
        SuperPublic.defaultMethod(); // ✅ 合法:同包访问
    }
}

但如果尝试从另一个包中访问,编译器就会报错:

package com.example.another;

import com.example.access.SuperPublic;

public class ExternalClass {
    public ExternalClass() {
        SuperPublic.defaultMethod(); // ❌ 编译错误:不在同一包
    }
}

所以,如果你希望某些工具方法只在模块内部使用,又不想写成 private(因为多个类要用),那默认访问就是最合适的——简单粗暴且安全。


3. public

public 是最开放的访问级别,意味着“对全世界可见”。

一旦一个类、方法或字段被声明为 public,所有其他包中的类都可以通过导入来访问它。

package com.example.access;

public class SuperPublic {
    public static void publicMethod() {
        System.out.println("This is a public method");
    }
}

在不同包中也能顺利调用:

package com.example.another;

import com.example.access.SuperPublic;

public class AnotherPublic {
    public AnotherPublic() {
        SuperPublic.publicMethod(); // ✅ 成功调用,跨包访问
    }
}

⚠️ 但要注意:public 应谨慎使用,尤其是暴露给外部 API 的接口。一旦发布,就不能轻易修改,否则会破坏兼容性。

📌 小贴士:关于 public 在类、接口、嵌套类中的具体行为,可参考 Java public 关键字详解


4. private

private 是最严格的访问控制,仅限本类内部访问

这是实现封装的核心手段。数据隐藏、内部逻辑隔离,都靠它。

package com.example.access;

public class SuperPublic {
    static private void privateMethod() {
        System.out.println("This is private");
    }
    
    private void anotherPrivateMethod() {
        privateMethod(); // ✅ 合法:同一类内调用
    }
}

任何外部类(包括子类)都无法访问这些成员:

package com.example.another;

import com.example.access.SuperPublic;

public class SubClass extends SuperPublic {
    public SubClass() {
        SuperPublic.privateMethod(); // ❌ 编译错误:无法访问 private 方法
    }
}

✅ 推荐实践:**默认所有字段和辅助方法都声明为 private**,除非有明确理由需要放宽访问权限。

📌 想了解 private 在字段、构造器、内部类中的更多细节?看这篇 Java private 关键字深度解析


5. protected

protected 处于 publicprivate 之间,是一种“家族特权”式的访问控制。

它的规则是:

  • ✅ 同一个包内的所有类可以访问
  • ✅ 不同包中的子类也可以访问(即使不在同一个包)

来看例子:

package com.example.access;

public class SuperPublic {
    static protected void protectedMethod() {
        System.out.println("This is protected");
    }
}

子类即使在不同包中,也能访问该方法:

package com.example.another;

import com.example.access.SuperPublic;

public class AnotherSubClass extends SuperPublic {
    public AnotherSubClass() {
        SuperPublic.protectedMethod(); // ✅ 合法:子类访问 protected 方法
    }
}

但注意:非子类的外部类仍然不能访问:

public class UnrelatedClass {
    public UnrelatedClass() {
        SuperPublic.protectedMethod(); // ❌ 编译错误:非子类且跨包
    }
}

✅ 使用场景:当你希望子类继承并扩展某些功能,但又不想完全公开给所有类时,protected 是最佳选择。

📌 更多关于 protected 在字段、方法、内部类中的行为,请查看 Java protected 访问修饰符详解


6. 访问级别对比总结

下表清晰地展示了四种访问修饰符的权限范围:

修饰符 本类 同包 子类 全世界(跨包非子类)
public
protected
default
private

📌 关键点:

  • 所有修饰符都保证“本类可访问”
  • protected 的“子类访问”能力是其最大特点
  • default 实际上就是“同包可见”
  • private 封闭性最强,适合隐藏实现细节

7. 修饰符的标准顺序(Canonical Order)

虽然 Java 不强制要求修饰符的书写顺序,但 Java 语言规范(JLS)推荐了一套标准顺序,有助于统一代码风格,提升可读性。

✅ 字段修饰符推荐顺序:

  1. 注解(Annotation)
  2. 访问修饰符(public / protected / private
  3. static
  4. final
  5. transient
  6. volatile

示例:

@Id
private static final long ID = 1;

这个写法完全符合 JLS 推荐的 canonical order。

✅ 类修饰符推荐顺序:

  1. 注解
  2. 访问修饰符
  3. abstract
  4. static
  5. final
  6. strictfp

✅ 方法修饰符推荐顺序:

  1. 注解
  2. 访问修饰符
  3. abstract
  4. static
  5. final
  6. synchronized
  7. native
  8. strictfp

⚠️ 注意:并非所有修饰符都能共存。例如:

  • publicprotectedprivate 三者互斥
  • abstractfinal 不能同时用于类
  • staticabstract 不能同时用于方法

🔧 实用技巧:像 IntelliJ IDEA 这类主流 IDE,在格式化代码时会自动调整修饰符顺序。只需一键 Ctrl + Alt + L,立刻合规。

📌 想了解 static final 的正确顺序?参考 Java static final 修饰符顺序规范


8. 总结

访问修饰符是 Java 面向对象编程的基石之一,合理使用能极大提升代码质量。

✅ 核心建议:

  • 优先使用最严格的访问级别,即默认从 private 开始
  • 只有真正需要对外暴露的 API 才使用 public
  • protected 适用于受控继承场景
  • 包级访问(default)适合模块内部协作

❌ 常见误区:

  • 所有方法都写成 public,导致封装失效
  • 忽视修饰符顺序,影响代码一致性
  • protected 的跨包子类访问机制理解不清

所有示例代码已上传至 GitHub:https://github.com/example-java/tutorials/tree/master/core-java-modules/core-java-lang-oop-modifiers


原始标题:Access Modifiers in Java | Baeldung