Appearance
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 visible 或 The 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 visible 或 The 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); // 正确
}
}最佳实践
属性使用 private:将属性设为 private,通过公共的 getter 和 setter 方法访问
方法使用适当的权限:根据需要选择合适的权限修饰符
- 公共接口使用 public
- 子类需要访问的使用 protected
- 同一个包使用的使用 default
- 只有本类使用的使用 private
类使用 public 或 default:
- 需要被其他包访问的类使用 public
- 只在同一个包中使用的类使用 default
构造方法使用适当的权限:
- 需要被其他类直接调用的构造方法使用 public
- 只在同一个包中使用的构造方法使用 default
- 只在本类中使用的构造方法使用 private(如单例模式)
遵循封装原则:通过权限修饰符实现封装,保护数据的安全性
总结
权限修饰符是 Java 中用于控制类、属性、方法和构造方法访问权限的关键字。Java 提供了四种权限修饰符:public、protected、default 和 private。
权限修饰符的访问范围:
- public:任何类都可以访问
- protected:同一个包或子类可以访问
- default:同一个包可以访问
- private:只有本类可以访问
通过合理使用权限修饰符,可以实现封装,保护数据的安全性,提高代码的可维护性和可扩展性。
