Java中public、protected、package-private和private的区别

Java中public、protected、package-private和private的区别

技术背景

在Java编程中,访问修饰符(access modifiers)是实现封装和信息隐藏的重要工具。封装是面向对象编程的四大特性之一,它可以将数据和操作数据的方法绑定在一起,并对外部隐藏对象的内部实现细节,从而提高代码的安全性和可维护性。Java提供了四种访问修饰符:publicprotectedpackage-private(默认,无修饰符)和private,它们分别用于控制类、方法、字段等的访问权限。

实现步骤

1. 明确访问修饰符的权限范围

以下表格总结了不同访问修饰符的访问权限:

修饰符同一类中同一包中不同包的子类不同包的非子类
public✔️✔️✔️✔️
protected✔️✔️✔️
package-private(无修饰符)✔️✔️
private✔️

2. 根据需求选择合适的访问修饰符

  • private:当某个成员(字段、方法、构造函数等)只在类的内部使用,不希望被外部访问时,使用private修饰符。这样可以确保类的内部实现细节对外部隐藏,提高代码的安全性和可维护性。
  • package-private:如果某个成员只需要在同一个包内的其他类中访问,而不希望被其他包的类访问,可以不使用任何修饰符,即采用默认的package-private访问级别。
  • protected:当某个成员需要在同一个包内的其他类中访问,并且还允许不同包的子类访问时,使用protected修饰符。
  • public:如果某个成员需要被所有类访问,无论这些类是否在同一个包中,都可以使用public修饰符。

核心代码

以下是不同访问修饰符的使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 定义一个父类
package fatherpackage;

public class Father {
// private字段,只能在类内部访问
private int privateField = 1;
// package-private字段,同一包内的类可以访问
int packagePrivateField = 2;
// protected字段,同一包内的类和不同包的子类可以访问
protected int protectedField = 3;
// public字段,所有类都可以访问
public int publicField = 4;

// private方法,只能在类内部访问
private void privateMethod() {
System.out.println("Private method");
}

// package-private方法,同一包内的类可以访问
void packagePrivateMethod() {
System.out.println("Package-private method");
}

// protected方法,同一包内的类和不同包的子类可以访问
protected void protectedMethod() {
System.out.println("Protected method");
}

// public方法,所有类都可以访问
public void publicMethod() {
System.out.println("Public method");
}
}

// 定义一个子类,位于不同的包中
package sonpackage;

import fatherpackage.Father;

public class Son extends Father {
public void testAccess() {
// 可以访问父类的protected和public成员
System.out.println(protectedField);
System.out.println(publicField);
protectedMethod();
publicMethod();

// 不能访问父类的private和package-private成员
// System.out.println(privateField); // 编译错误
// System.out.println(packagePrivateField); // 编译错误
// privateMethod(); // 编译错误
// packagePrivateMethod(); // 编译错误
}
}

// 定义一个不同包的非子类
package otherpackage;

import fatherpackage.Father;

public class OtherClass {
public void testAccess() {
Father father = new Father();
// 只能访问父类的public成员
System.out.println(father.publicField);
father.publicMethod();

// 不能访问父类的private、package-private和protected成员
// System.out.println(father.privateField); // 编译错误
// System.out.println(father.packagePrivateField); // 编译错误
// System.out.println(father.protectedField); // 编译错误
// father.privateMethod(); // 编译错误
// father.packagePrivateMethod(); // 编译错误
// father.protectedMethod(); // 编译错误
}
}

最佳实践

  • 遵循最小权限原则:在设计类和成员时,应尽量使用最严格的访问修饰符,只在必要时放宽访问权限。这样可以减少代码的耦合度,提高代码的安全性和可维护性。
  • 使用private修饰字段:将类的字段声明为private,并提供publicgettersetter方法来访问和修改字段的值。这样可以对字段的访问进行控制,避免外部直接修改字段的值,从而保证数据的完整性。
  • 合理使用protected修饰符:当需要在子类中扩展父类的功能时,可以将父类的某些方法声明为protected,以便子类可以重写这些方法。
  • 使用public修饰公共接口:将类的公共接口(如公共方法、公共常量等)声明为public,以便其他类可以使用这些接口。

常见问题

1. protected修饰符的理解误区

很多人认为protected修饰的成员只能被子类访问,实际上,protected修饰的成员不仅可以被不同包的子类访问,还可以被同一包内的所有类访问。

2. 接口中的访问修饰符

在接口中,所有的字段默认都是public static final,所有的方法默认都是public abstract。接口中不能使用privateprotected修饰符。

3. 继承时的访问权限问题

子类重写父类的方法时,访问权限不能比父类的方法更严格。例如,如果父类的方法是public的,子类重写该方法时也必须是public的。


Java中public、protected、package-private和private的区别
https://119291.xyz/posts/2025-04-22.differences-between-java-access-modifiers/
作者
ww
发布于
2025年4月23日
许可协议