Java访问修饰符:public、private、protected,控制可见性

在Java中,我们写的代码是由一个个类和类的成员(方法、变量等)组成的。为了让代码更安全、更易于维护,Java提供了访问修饰符来控制这些成员的可见范围——也就是哪些地方可以访问它们,哪些地方不能。这篇文章我们就来聊聊最常用的三个访问修饰符:publicprivateprotected,看看它们是如何控制可见性的。

为什么需要访问修饰符?

想象一下,如果所有类的成员都能被任何地方直接访问,那么代码可能会被随意修改或误操作。比如,一个银行账户的余额如果可以被任何人直接修改,那会有多危险?访问修饰符就像“门禁”,帮我们控制谁能进、谁不能进。

1. public:公开的,所有地方都能访问

public 是最“开放”的修饰符,表示成员对所有类都是可见的,无论在同一个包还是不同包中。

例子
假设我们有一个类 Person,里面有一个 public 方法,其他类无论在哪里都能调用它。

// 类 Person 在包 com.example 下
package com.example;

public class Person {
    // public 方法,所有地方都能调用
    public void sayHello() {
        System.out.println("Hello!");
    }
}

// 另一个类 OtherClass 在不同包 com.test 下
package com.test;

import com.example.Person; // 导入 Person 类

public class OtherClass {
    public static void main(String[] args) {
        Person person = new Person();
        person.sayHello(); // 成功调用!public 方法跨包可访问
    }
}

结论public 成员可以被任何类直接访问,包括不同包的类。

2. private:私有的,仅限当前类内部访问

private 是最“严格”的修饰符,表示成员只能在定义它的类内部访问,其他类(包括同一包的其他类)都无法直接访问。

例子
假设 Person 类有一个 private 变量,其他类(即使在同一个包)也无法直接读取或修改它。

// 类 Person 在包 com.example 下
package com.example;

class Person {
    private String name; // 私有变量,只能 Person 自己访问

    private void printName() { // 私有方法,只能 Person 自己调用
        System.out.println("Name: " + name);
    }

    // 提供 public 方法让外部间接访问私有变量
    public void setName(String n) {
        name = n;
    }

    public void getName() {
        printName(); // 内部调用私有方法
    }
}

// 同一包中的类 OtherClass,尝试访问 Person 的 private 成员
package com.example;

public class OtherClass {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("Alice"); // 正确:通过 public 方法设置
        person.getName(); // 正确:通过 public 方法获取

        // 错误!private 成员不能直接访问
        // System.out.println(person.name); // 编译报错:无法访问私有成员
        // person.printName(); // 编译报错:无法访问私有方法
    }
}

结论private 成员只能在类内部访问,外部类必须通过类提供的 public 方法(如 getter/setter)间接访问。

3. protected:受保护的,同包可访问,子类可访问

protected 修饰符的可见性介于 publicprivate 之间,需要区分两种情况:
- 同包内:和 public 类似,同一个包中的类可以直接访问 protected 成员。
- 不同包的子类:如果一个类继承了定义 protected 成员的父类,那么子类可以通过继承的方式访问这些成员(即使子类和父类不在同一个包)。

例子1:同包内访问

// 类 A 和类 B 在同一个包 com.example 下
package com.example;

class A {
    protected int age = 20; // 受保护的变量,同包可访问
}

class B {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.age); // 正确:同包可直接访问
    }
}

例子2:不同包的子类访问

// 父类 Person 在包 com.example 下
package com.example;

public class Person {
    protected String name; // 受保护的变量

    protected void showName() {
        System.out.println("Name: " + name);
    }
}

// 子类 Student 在不同包 com.test 下,继承自 Person
package com.test;

import com.example.Person; // 导入父类

public class Student extends Person {
    public void displayInfo() {
        name = "Bob"; // 子类可直接访问父类的 protected 变量
        showName();   // 子类可直接调用父类的 protected 方法
    }
}

// 测试类,尝试访问非子类的 protected 成员
package com.test;

import com.example.Person;

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        // 错误!Test 不是 Person 的子类,不同包无法访问 protected 成员
        // System.out.println(person.name); // 编译报错
    }
}

结论protected 成员在同包内不同包的子类中可以访问,但非子类的不同包类无法访问。

4. 默认修饰符(无修饰符):同包可访问

如果一个成员没有任何修饰符(即“默认”修饰符),它的可见范围是仅在同一个包内可访问,不同包的类无法访问。

例子

// 类 A 和类 B 在同一个包 com.example 下
package com.example;

class A {
    int count = 10; // 默认修饰符,同包可访问
}

class B {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.count); // 正确:同包可直接访问
    }
}

// 不同包的类尝试访问默认成员
package com.test;

import com.example.A;

public class Test {
    public static void main(String[] args) {
        A a = new A();
        // 错误!不同包无法访问默认成员
        // System.out.println(a.count); // 编译报错
    }
}

结论:默认修饰符成员仅在同包内可见,不同包不可访问。

总结:访问修饰符对比表

修饰符 同包内类 不同包的非子类 不同包的子类 其他包类
public ✅ 是 ✅ 是 ✅ 是 ✅ 是
private ❌ 否 ❌ 否 ❌ 否 ❌ 否
protected ✅ 是 ❌ 否 ✅ 是 ❌ 否
默认 ✅ 是 ❌ 否 ❌ 否 ❌ 否

实际开发中的建议

  • 成员变量优先用 private:通过 public 方法(如 getter/setter)控制访问,既能保证数据安全,又能在方法中添加逻辑(比如验证数据)。
  • 控制类的可见性:如果类只在当前包内使用,用默认修饰符;如果需要被其他包的类使用,用 public
  • protected 用于继承场景:比如父类想让子类访问某些成员,但又不想让其他类访问,就用 protected

掌握访问修饰符,是写出安全、清晰代码的第一步!

小夜