Skip to content

11.6 权限修饰符(public、protected、default、private)

权限修饰符的概念

权限修饰符(Access Modifiers)是 Java 中用于控制类、属性、方法和构造方法访问权限的关键字。Java 提供了四种权限修饰符:public、protected、default(默认)和 private。

权限修饰符的访问范围

修饰符同一类同一包子类(不同包)其他包
public
protected
default
private

权限修饰符的使用

1. public 修饰符

public 修饰符表示公共的,任何类都可以访问。

示例:

java
public class PublicExample {
    public String publicField = "public field";
    
    public void publicMethod() {
        System.out.println("public method");
    }
}

// 其他类可以访问
public class OtherClass {
    public void accessPublic() {
        PublicExample example = new PublicExample();
        System.out.println(example.publicField);
        example.publicMethod();
    }
}

2. protected 修饰符

protected 修饰符表示受保护的,同一个包或子类可以访问。

示例:

java
package com.example;

public class ProtectedExample {
    protected String protectedField = "protected field";
    
    protected void protectedMethod() {
        System.out.println("protected method");
    }
}

// 同一个包中的类可以访问
package com.example;

public class SamePackageClass {
    public void accessProtected() {
        ProtectedExample example = new ProtectedExample();
        System.out.println(example.protectedField);
        example.protectedMethod();
    }
}

// 不同包中的子类可以访问
package com.example.other;

import com.example.ProtectedExample;

public class SubClass extends ProtectedExample {
    public void accessProtected() {
        System.out.println(protectedField); // 可以访问父类的 protected 属性
        protectedMethod(); // 可以访问父类的 protected 方法
    }
}

// 不同包中的非子类不能访问
package com.example.other;

import com.example.ProtectedExample;

public class OtherPackageClass {
    public void accessProtected() {
        ProtectedExample example = new ProtectedExample();
        // 错误:不能访问 protected 属性
        // System.out.println(example.protectedField);
        // 错误:不能访问 protected 方法
        // example.protectedMethod();
    }
}

3. default 修饰符

default 修饰符表示默认的,同一个包可以访问。default 修饰符不需要显式声明,不使用任何修饰符就是默认权限。

示例:

java
package com.example;

class DefaultExample {
    String defaultField = "default field";
    
    void defaultMethod() {
        System.out.println("default method");
    }
}

// 同一个包中的类可以访问
package com.example;

public class SamePackageClass {
    public void accessDefault() {
        DefaultExample example = new DefaultExample();
        System.out.println(example.defaultField);
        example.defaultMethod();
    }
}

// 不同包中的类不能访问
package com.example.other;

import com.example.DefaultExample;

public class OtherPackageClass {
    public void accessDefault() {
        // 错误:不能访问默认权限的类
        // DefaultExample example = new DefaultExample();
    }
}

4. private 修饰符

private 修饰符表示私有的,只有本类可以访问。

示例:

java
public class PrivateExample {
    private String privateField = "private field";
    
    private void privateMethod() {
        System.out.println("private method");
    }
    
    // 本类可以访问私有成员
    public void accessPrivate() {
        System.out.println(privateField);
        privateMethod();
    }
}

// 其他类不能访问私有成员
public class OtherClass {
    public void accessPrivate() {
        PrivateExample example = new PrivateExample();
        // 错误:不能访问私有属性
        // System.out.println(example.privateField);
        // 错误:不能访问私有方法
        // example.privateMethod();
        
        // 可以通过公共方法间接访问
        example.accessPrivate();
    }
}

权限修饰符的应用场景

1. public 修饰符

  • :需要被其他包访问的类
  • 属性:需要被其他类直接访问的属性
  • 方法:需要被其他类直接调用的方法
  • 构造方法:需要被其他类直接调用的构造方法

2. protected 修饰符

  • 属性:需要被子类访问的属性
  • 方法:需要被子类重写或访问的方法
  • 构造方法:需要被子类调用的构造方法

3. default 修饰符

  • :只在同一个包中使用的类
  • 属性:只在同一个包中使用的属性
  • 方法:只在同一个包中使用的方法
  • 构造方法:只在同一个包中使用的构造方法

4. private 修饰符

  • 属性:只在本类中使用的属性
  • 方法:只在本类中使用的方法
  • 构造方法:只在本类中使用的构造方法(如单例模式)

示例:权限修饰符的综合使用

示例 1:封装

java
public class Person {
    // 私有属性,只能在本类中访问
    private String name;
    private int age;
    
    // 公共构造方法,任何类都可以访问
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 公共方法,任何类都可以访问
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        if (age >= 0 && age <= 150) {
            this.age = age;
        }
    }
    
    // 受保护方法,同一个包或子类可以访问
    protected void protectedMethod() {
        System.out.println("Protected method in Person");
    }
    
    // 默认方法,同一个包可以访问
    void defaultMethod() {
        System.out.println("Default method in Person");
    }
    
    // 私有方法,只有本类可以访问
    private void privateMethod() {
        System.out.println("Private method in Person");
    }
}

public class Student extends Person {
    private int studentId;
    
    public Student(String name, int age, int studentId) {
        super(name, age);
        this.studentId = studentId;
    }
    
    public void accessParentMembers() {
        // 可以访问父类的受保护方法
        protectedMethod();
        
        // 不能访问父类的默认方法(不同包)
        // defaultMethod();
        
        // 不能访问父类的私有方法
        // privateMethod();
    }
}

示例 2:继承

java
package com.example.parent;

public class Parent {
    public String publicField = "public field";
    protected String protectedField = "protected field";
    String defaultField = "default field";
    private String privateField = "private field";
    
    public void publicMethod() {
        System.out.println("public method in Parent");
    }
    
    protected void protectedMethod() {
        System.out.println("protected method in Parent");
    }
    
    void defaultMethod() {
        System.out.println("default method in Parent");
    }
    
    private void privateMethod() {
        System.out.println("private method in Parent");
    }
}

package com.example.child;

import com.example.parent.Parent;

public class Child extends Parent {
    public void accessParentMembers() {
        // 可以访问父类的公共属性
        System.out.println(publicField);
        
        // 可以访问父类的受保护属性
        System.out.println(protectedField);
        
        // 不能访问父类的默认属性(不同包)
        // System.out.println(defaultField);
        
        // 不能访问父类的私有属性
        // System.out.println(privateField);
        
        // 可以访问父类的公共方法
        publicMethod();
        
        // 可以访问父类的受保护方法
        protectedMethod();
        
        // 不能访问父类的默认方法(不同包)
        // defaultMethod();
        
        // 不能访问父类的私有方法
        // privateMethod();
    }
}

常见问题

1. 访问权限不足

症状:编译错误:The field Parent.field is not visibleThe method Parent.method() is not visible

解决方案:根据需要调整权限修饰符,或通过公共方法间接访问

示例:

java
public class Parent {
    private int privateField;
    
    // 错误:其他类不能直接访问私有属性
    // public class Child {
    //     public void access() {
    //         Parent parent = new Parent();
    //         parent.privateField = 10; // 编译错误
    //     }
    // }
    
    // 正确:通过公共方法间接访问
    public int getPrivateField() {
        return privateField;
    }
    
    public void setPrivateField(int privateField) {
        this.privateField = privateField;
    }
}

2. 权限修饰符使用不当

症状:代码安全性问题或访问权限错误

解决方案:根据实际需求选择合适的权限修饰符

示例:

java
// 错误:使用 public 修饰私有属性
// public class Person {
//     public String name; // 不应该使用 public
// }

// 正确:使用 private 修饰私有属性,提供公共的 getter 和 setter 方法
public class Person {
    private String name;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}

3. 子类无法访问父类的成员

症状:编译错误:The field Parent.field is not visibleThe method Parent.method() is not visible

解决方案:将父类的成员设置为 protected 或 public

示例:

java
public class Parent {
    // 错误:子类无法访问私有成员
    // private String field;
    
    // 正确:子类可以访问受保护成员
    protected String field;
}

public class Child extends Parent {
    public void access() {
        System.out.println(field); // 正确
    }
}

最佳实践

  1. 属性使用 private:将属性设为 private,通过公共的 getter 和 setter 方法访问

  2. 方法使用适当的权限:根据需要选择合适的权限修饰符

    • 公共接口使用 public
    • 子类需要访问的使用 protected
    • 同一个包使用的使用 default
    • 只有本类使用的使用 private
  3. 类使用 public 或 default

    • 需要被其他包访问的类使用 public
    • 只在同一个包中使用的类使用 default
  4. 构造方法使用适当的权限

    • 需要被其他类直接调用的构造方法使用 public
    • 只在同一个包中使用的构造方法使用 default
    • 只在本类中使用的构造方法使用 private(如单例模式)
  5. 遵循封装原则:通过权限修饰符实现封装,保护数据的安全性

总结

权限修饰符是 Java 中用于控制类、属性、方法和构造方法访问权限的关键字。Java 提供了四种权限修饰符:public、protected、default 和 private。

权限修饰符的访问范围:

  • public:任何类都可以访问
  • protected:同一个包或子类可以访问
  • default:同一个包可以访问
  • private:只有本类可以访问

通过合理使用权限修饰符,可以实现封装,保护数据的安全性,提高代码的可维护性和可扩展性。

© 2026 编程马·菜鸟教程 版权所有