CodeGym /课程 /JAVA 25 SELF /访问修饰符相关错误

访问修饰符相关错误

JAVA 25 SELF
第 23 级 , 课程 2
可用

1. 引言

在 Java 中,访问修饰符就像房子里的锁系统。它们决定了谁、从哪里可以“进入”你的房间(或者访问你类的字段/方法)。如果所有的门都开着——任何人都可以进来改点什么。如果全都锁上——没人能破坏什么,但你自己某个时候也可能被困住。

提醒一下,在 Java 中有四个主要的访问级别:

修饰符 类内部可见 包内可见 子类可见 其他包可见
private
(package)
protected
(通过继承)
public

(package)——指未显式声明修饰符。这样的类成员只在同一个包内可见。

2. 访问修饰符的常见错误

错误 1:使用默认修饰符的字段和方法(package-private

最常见的新手错误——忘记写访问修饰符。结果字段或方法在整个包内都可见,而你本来并不打算这样。这可能导致同一包中与您的类无关的其他类修改你的对象内部状态。

// 错误:字段 name 未受保护!
class User {
    String name; // package-private!
}

于是,同一包中的任何类都可以这样写:

User user = new User();
user.name = "John"; // 没有限制!

错误 2:破坏封装——将字段设为 public

第二常见的错误——把类的字段声明为 public。学习或写小示例时这样做看似方便,但在真实项目中几乎总是不妥。你会失去对于谁在如何修改你数据的控制。

public class Account {
    public double balance; // 危险!
}

于是任何代码都可以这样做:

Account acc = new Account();
acc.balance = -1000000; // 现在谁该负责?

错误 3:缺少 getter 和 setter

有时开发者把字段设为 private,却忘了添加相应的访问方法。结果在一些本应合理的场景下也无法获取或修改它们的值。

public class Product {
    private String name;
    // 既没有 getName(),也没有 setName()
}

错误 4:从其他类访问 private 成员

如果你把字段或方法声明为 private,就不能从其他类访问它,即使在同一个包中也是如此。新手常常纳闷为什么“看不到”这个字段。

public class User {
    private String password;
}

public class UserService {
    public void resetPassword(User user) {
        // user.password = "123"; // 编译错误!
    }
}

错误 5:对 protected 的误解

很多人认为 protected 意味着“凡是有继承的地方都能看到”。但在 Java 中,包外对 protected 成员的访问只能通过继承,且仅限子类。这一细节很容易被忽略。

package animals;

public class Animal {
    protected void sleep() {}
}

package zoo;
import animals.Animal;

public class Dog extends Animal {
    public void test() {
        sleep(); // OK——子类
    }
}

public class NotADog {
    public void test() {
        Animal a = new Animal();
        // a.sleep(); // 错误:不是子类!
    }
}

3. 正确做法:最佳实践

规则 1:默认将字段设为 private

这是封装的核心原则。字段应对除本类以外的所有人隐藏。若需要提供访问——使用 getter/setter。

public class Book {
    private String title;
    private int pages;

    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

规则 2:只公开必要的方法

若方法需要对外可见——将其设为 public。若只在包内需要——保持为 package-private。若仅供子类使用——使用 protected

规则 3:尽量缩小可见范围

可见范围越小,发生意外错误和“未经邀请的访问”的概率越低。没有必要就不要把方法和字段设为 public

规则 4:通过 getter 和 setter 控制访问

这允许在读取/写入字段时添加额外逻辑,例如校验。

public class Account {
    private double balance;

    public void setBalance(double balance) {
        if (balance < 0) {
            throw new IllegalArgumentException("余额不能为负数!");
        }
        this.balance = balance;
    }

    public double getBalance() {
        return balance;
    }
}

规则 5:不要暴露内部实现

如果你的字段是数组或列表,不要通过 getter 直接返回它——要返回副本,或只提供必要的方法。

public class Team {
    private List<String> members = new ArrayList<>();

    // 正确做法:
    public List<String> getMembers() {
        return new ArrayList<>(members); // 返回副本
    }
}

4. 实战示例

假设我们有一个类 LibraryUser,用于描述图书馆用户。

错误实现示例

public class LibraryUser {
    public String name;
    public int borrowedBooks;
}

这样任何代码都能对对象为所欲为:

LibraryUser user = new LibraryUser();
user.name = null;
user.borrowedBooks = -10; // 逻辑?这算什么逻辑?

带封装的正确实现示例

public class LibraryUser {
    private String name;
    private int borrowedBooks;

    public LibraryUser(String name) {
        this.name = name;
        this.borrowedBooks = 0;
    }

    public String getName() {
        return name;
    }

    public int getBorrowedBooks() {
        return borrowedBooks;
    }

    public void borrowBook() {
        borrowedBooks++;
    }

    public void returnBook() {
        if (borrowedBooks > 0) {
            borrowedBooks--;
        }
    }
}

现在外部代码不能直接修改借书数量或用户名。一切只能通过类的方法来控制。

5. 实现中的特点与细节

有时把字段设为 public 看起来比写一堆 getter/setter 更省事。但这是个陷阱!公开字段就像把家门敞开:是的,方便,但并不安全。

另一个细节——并不总要为所有字段都提供 getter 和 setter。如果对象创建后该字段不应再改变,只提供 getter,并把字段设为 final

public class Passport {
    private final String number;

    public Passport(String number) {
        this.number = number;
    }

    public String getNumber() {
        return number;
    }
}

还要记住:如果类被声明为 public,文件名必须与类名相同!这并不完全是关于访问修饰符的问题,但却是新手非常常见的错误。

6. 使用访问修饰符时的常见错误

错误 1:忘了给字段或方法写访问修饰符。 结果该字段或方法在整个包内都可见,即使你并不想这样。即使 IDE 不报错,也要显式写出修饰符。

错误 2:把所有字段都声明为 public 这会破坏封装,让你的代码变得脆弱且不可预测。示例中为“图省事”而养成的习惯不应出现在生产代码中。

错误 3:试图从其他类访问 private 字段。 Java 不会允许这么做——编译器会保护你。但如果你还想通过反射“绕过”它——请想一想,为什么会产生这样的需求。

错误 4:以为只要有继承,protected 成员到处都能访问。 实际上,在包外只能由子类访问,并且只能通过 this 或子类对象来访问。

错误 5:通过 getter 返回内部集合。 如果返回内部数组或列表的引用,外部代码就能修改它,从而破坏类的不变量。

错误 6:通过 setter 设值却没有校验。 如果不验证输入值,对象可能进入不正确的状态(例如出现负余额)。

错误 7:方法的可见范围过宽。 有时把方法设为 public,但其实它们只在包内或类内才需要。这会暴露不必要的 API,并增加维护成本。

评论 (1)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
ncksllpo 级别 44,Cherkasy,Ukraine
10 二月 2026
任务不可以重新做💔