Menu

Java 访问修饰符:public、private、protected 与默认

Java 的四种访问级别(public、private、protected 和包私有)如何控制其他代码能看到和修改什么。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

谁可以访问你的代码

访问修饰符是写在类、字段、方法或构造方法前面的关键字,决定还有谁可以使用它。它是封装的基础:把类内部杂乱的细节隐藏起来,只公开那些你信得过、允许其他代码调用的部分。

Java 有四个级别,从最开放到最严格依次是:public、protected、默认(完全不写关键字)和 private。把它们用对了,类在以后修改时就很安全,因为外部没有任何代码依赖你从未承诺保留的细节。

private:只在类内部可见

private 是最严格的级别。private 成员只能被同一个类内部的代码访问:子类不行,同一个包里的其他类也不行,谁都不行。大多数字段都应该是 private 的。

balance 是 private 的,所以修改它的唯一途径是 deposit,而 deposit 会拒绝负数金额。如果 balance 是 public 的,任何代码都可以写 account.balance = -9999,完全绕过检查。这道防线正是隐藏字段的意义所在。

试着取消 main 中 account.balance = 500; 的注释,你会得到一个编译错误:balance has private access in BankAccount。

public:在任何地方都可见

public 是另一个极端:任何人在任何地方都能使用该成员。打算让其他代码调用的方法通常是 public 的。当类本身需要被其他包访问时,类也是 public 的。

常见的模式是私有字段,公有方法,有时也叫类的公共 API。字段保存别人不该乱动的状态;方法则是受控的进出通道。上面的 getBalance 和 deposit 正是如此。

默认(包私有):完全不写关键字

如果不写任何修饰符,就得到默认访问,也叫包私有。该成员对同一个包中的每个类都可见,对包外的一切都不可见。这个级别没有对应的关键字,不写关键字本身就是这个级别。

class Invoice {       // no modifier -> visible only within this package
    int amount;       // no modifier -> package-private field
}

很多初学者在这里栽跟头:漏写 public 并不会让成员变成 private,而是变成包私有。一个你本想保密的字段,仍然可以被同一个包里的任何类完整地读写。如果要真正隐藏它,必须明确写上 private。

默认访问对某个包内部的辅助类非常有用:你不对外公开它们,但包内相互协作的类仍然可以随意使用。

protected:包内加子类

protected 比默认访问再宽松一级。protected 成员在默认访问可见的地方(同一个包)都可见,而且对子类也可见,即使子类在另一个包里。它的设计用途是:与继承你的类的那些类共享,但不对整个世界公开。

Dog 能访问 name 和 sound(),因为它们是 protected 的,而 Dog 是子类。既不是子类、也不在同一个包里的外部代码仍然无法访问它们。设计一个打算被继承的类时才用 protected;否则优先用 private。

四个级别一览

下面是完整的对照表,从最严格到最开放:

修饰符同一个类同一个包子类(其他包)任何地方
private是否否否
默认是是否否
protected是是是否
public是是是是

一个简单的经验法则:从 private 开始,只有在确实需要更大范围的访问时才放宽。 以后放宽访问要比收紧容易得多,因为一旦其他代码开始依赖某个成员,就很难再收紧了。

类本身的修饰符

访问修饰符不只用于成员,也用于类,但顶层类(不嵌套在其他类中的类)只能是 public 或默认访问。你不能写顶层的 private 或 protected 类。

public class Order { ... }   // reachable from any package
class LineItem { ... }       // default - only this package can see it

public 顶层类必须放在以它命名的文件中(Order.java)。而嵌套类可以使用全部四种修饰符,所以上面的例子可以把内部类标记为 private 或默认访问。还有一个细节:返回包私有类型的 public 方法对外部调用者用处不大,所以要让公开的部分保持一致。

下一步:静态成员

到目前为止,这里的每个字段和方法都属于某个实例:先用 new 创建对象,再在对象上调用方法。但有时某个值或行为属于整个类,由所有实例共享,比如统计已创建了多少个对象的计数器。这就是 static 关键字的用途,也是下一页的内容。

常见问题

Java 的四种访问修饰符是什么?

public、private、protected 和默认(不写关键字,也叫包私有)。public 在任何地方都可见,private 只在同一个类内可见,protected 在包内以及子类中可见,默认访问只在同一个包内可见。

Java 中 public 和 private 有什么区别?

public 表示任何地方的任何代码都能访问该成员。private 表示只有同一个类内部的代码可以访问,子类和其他类连看都看不到它。通常把字段设为 private,再通过 public 方法对外提供访问。

Java 字段没有访问修饰符是什么意思?

不写关键字就是默认(包私有)访问:该成员对同一个包中的每个类都可见,但在包外不可见。它比 public 严格,比 private 宽松,而且很容易因为疏忽而漏写,所以要有意识地使用它。

Coddy 编程语言插图

和 Coddy 一起学编程

开始