跳到主要内容

Java 访问修饰符

在Java的面向对象编程中,访问修饰符是控制类、方法、变量访问权限的关键元素。它们决定了代码的封装级别,是实现信息隐藏原则的重要工具。本文将详细介绍Java中的四种访问修饰符,帮助初学者理解它们的作用范围和适用场景。

什么是访问修饰符?

访问修饰符是用来限定类、方法或变量的访问范围的关键字。Java提供了四种访问控制级别,从最开放到最严格依次为:

  1. public(公共的)
  2. protected(受保护的)
  3. 默认(无修饰符,也称为包访问权限)
  4. private(私有的)

四种访问修饰符详解

1. public(公共的)

public 是最宽松的访问级别,允许任何类访问。

  • 作用范围:任何类都可以访问
  • 适用场景:需要对外公开的API接口、工具类方法等
java
public class User {
public String username;

public void printUsername() {
System.out.println("用户名:" + username);
}
}

任何其他类都可以访问 User 类、它的 username 字段和 printUsername() 方法。

2. protected(受保护的)

protected 修饰符允许同包内的类及其子类(无论位于哪个包)访问。

  • 作用范围:同一包内的所有类 + 不同包中的子类
  • 适用场景:需要在继承体系中共享,但不想对外公开的成员
java
public class Animal {
protected String name;

protected void eat() {
System.out.println(name + " is eating");
}
}

// 同一个包或者不同包的子类
public class Dog extends Animal {
public void dogEat() {
name = "Buddy"; // 可以访问父类的protected成员
eat(); // 可以访问父类的protected方法
}
}

3. 默认(无修饰符)

默认访问级别(也称为包访问权限)没有显式的关键词,不编写任何访问修饰符时即为默认级别。

  • 作用范围:仅同一包内的类可以访问
  • 适用场景:包内实现细节,不希望包外访问的内容
java
class Helper {  // 默认访问权限的类
int count; // 默认访问权限的变量

void increment() { // 默认访问权限的方法
count++;
}
}

// 同一包内的另一个类可以访问Helper
public class Calculator {
void calculate() {
Helper helper = new Helper();
helper.count = 10; // 可以访问
helper.increment(); // 可以访问
}
}

如果 Calculator 类位于不同的包中,它将无法访问 Helper 类。

4. private(私有的)

private 是最严格的访问级别,只允许在声明它的类内部访问。

  • 作用范围:仅在声明它的类内部可访问
  • 适用场景:类的内部实现细节,需要完全隐藏的成员
java
public class BankAccount {
private double balance;
private String accountNumber;

public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}

public void deposit(double amount) {
if (amount > 0) {
balance += amount; // 可以访问私有变量
System.out.println("存款成功,当前余额: " + balance);
}
}

public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount; // 可以访问私有变量
System.out.println("取款成功,当前余额: " + balance);
} else {
System.out.println("取款失败,余额不足");
}
}

public double getBalance() {
return balance;
}
}

balanceaccountNumber 被声明为私有,只能在 BankAccount 类内部访问,这样可以保护账户余额不被外部直接修改。

访问级别总结

下表总结了四种访问修饰符的可访问范围:

实际应用案例

案例1: 封装用户信息

java
public class User {
private String username;
private String password;
private String email;

public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}

// 公开方法获取用户名
public String getUsername() {
return username;
}

// 公开方法设置用户名
public void setUsername(String username) {
if (username != null && username.length() >= 3) {
this.username = username;
} else {
System.out.println("用户名至少需要3个字符");
}
}

// 公开方法获取邮箱
public String getEmail() {
return email;
}

// 公开方法设置邮箱
public void setEmail(String email) {
if (email != null && email.contains("@")) {
this.email = email;
} else {
System.out.println("邮箱格式无效");
}
}

// 验证密码,但不允许直接获取密码
public boolean verifyPassword(String inputPassword) {
return password.equals(inputPassword);
}
}

在这个例子中:

  • usernamepasswordemail 被声明为私有,防止外部直接访问
  • 提供了公共的 getter 和 setter 方法来控制访问
  • password 只提供验证方法,没有提供 getter,增强了安全性

案例2: 继承与访问控制

java
// 图形类层次结构
public class Shape {
protected double area;

protected void calculateArea() {
// 基类中的通用计算逻辑
System.out.println("计算面积...");
}

public double getArea() {
return area;
}
}

public class Circle extends Shape {
private double radius;

public Circle(double radius) {
this.radius = radius;
calculateArea(); // 调用继承的protected方法
}

@Override
protected void calculateArea() {
area = Math.PI * radius * radius; // 访问继承的protected字段
System.out.println("圆的面积: " + area);
}
}

public class Rectangle extends Shape {
private double width;
private double height;

public Rectangle(double width, double height) {
this.width = width;
this.height = height;
calculateArea(); // 调用继承的protected方法
}

@Override
protected void calculateArea() {
area = width * height; // 访问继承的protected字段
System.out.println("矩形的面积: " + area);
}
}

在这个例子中:

  • Shape 类的 area 字段和 calculateArea() 方法使用 protected 修饰符
  • 子类可以访问和覆盖这些成员,但外部类不能直接访问
  • 每个子类都实现了自己的面积计算逻辑,展示了继承和多态的应用

如何选择适当的访问修饰符

选择访问修饰符时,可以遵循以下原则:

  1. 最小化权限原则:始终使用可能的最严格访问级别
  2. 对变量使用私有:几乎所有的实例变量应该被声明为 private
  3. 为外部API使用公共:需要被外部访问的方法应该被声明为 public
  4. 为继承设计使用受保护:子类需要访问的成员可以设为 protected
  5. 包内部实现使用默认:只在当前包内使用的内容可以使用默认访问级别
提示

遵循"最小化权限原则"是良好的编程习惯,它可以提高代码的安全性和可维护性。只有在确实需要时才提高访问级别。

常见误区与注意事项

  1. 混淆继承与访问控制

    • 子类继承了父类的所有成员,但不一定能访问所有成员
    • 私有成员虽然被继承,但子类无法直接访问
  2. 构造器的访问权限

    • 构造器也可以使用访问修饰符
    • 私有构造器常用于单例模式
    • 默认构造器会阻止其他包创建该类的实例
  3. 内部类的访问权限

    • 内部类可以访问外部类的所有成员,包括私有成员
    • 内部类自身也可以使用不同的访问修饰符

总结

Java的访问修饰符是实现封装和信息隐藏的重要工具。合理使用访问修饰符可以:

  • 控制代码的可见性和可访问性
  • 隐藏实现细节,只暴露必要的API
  • 防止外部代码对内部状态的不当修改
  • 使代码更安全、更易于维护和理解

理解和正确使用访问修饰符是编写高质量Java代码的基础,也是面向对象设计的重要部分。

练习题

  1. 编写一个 Car 类,包含私有字段 modelyearmileage,提供适当的构造器和访问器方法。
  2. 创建一个银行账户继承层次,包含基类 Account 和子类 SavingsAccountCheckingAccount,合理使用访问修饰符。
  3. 设计一个包含私有构造器的单例类 DatabaseConnection
进一步学习
  • 了解Java的包(package)概念及其与访问修饰符的关系
  • 学习Java的封装原则
  • 探索访问修饰符在接口和抽象类中的使用