访问权限
Java 访问权限修饰符详解
在 Java 中,访问权限修饰符用于控制类、属性、方法的可见范围,是封装特性的核心实现手段。合理使用访问权限可以隐藏内部实现细节、保护数据安全,并降低代码耦合度。Java 提供四种访问权限,从最大到最小依次为:public、protected、包访问权限(default,无修饰符)、private。
包(Package):访问权限的基础
包是类的组织单位,用于避免类名冲突并划分访问边界。一个类的全名是 “包名 + 类名”(如 java.util.ArrayList)。通过 import 语句可以简化类的使用(如 import java.util.ArrayList)。
- 同包类:位于同一包下的类,默认具有包访问权限。
- 不同包类:位于不同包下的类,需通过
public或protected权限才能访问。
四种访问权限详解
1. public(公共权限)
- 可见范围:所有类(本类、同包类、子类、非子类)均可访问。
- 适用场景:暴露给外部的接口(如
java.util.List的add方法)。
public class PublicDemo {
public String publicField = "公共属性";
public void publicMethod() {
System.out.println("公共方法");
}
}
// 任意类均可访问
public class OtherClass {
public static void main(String[] args) {
PublicDemo demo = new PublicDemo();
System.out.println(demo.publicField); // 合法
demo.publicMethod(); // 合法
}
}
2. protected(保护权限)
- 可见范围:本类、同包类、子类(无论是否同包)可访问,非子类不可访问。
- 适用场景:仅允许子类继承或同包类协作的成员(如模板方法中的辅助方法)。
package com.example.parent;
public class ProtectedDemo {
protected String protectedField = "保护属性";
protected void protectedMethod() {
System.out.println("保护方法");
}
}
// 同包类:可访问
package com.example.parent;
public class SamePackageClass {
public static void main(String[] args) {
ProtectedDemo demo = new ProtectedDemo();
System.out.println(demo.protectedField); // 合法
}
}
// 不同包子类:可访问
package com.example.child;
import com.example.parent.ProtectedDemo;
public class SubClass extends ProtectedDemo {
public void test() {
System.out.println(protectedField); // 合法(继承自父类)
protectedMethod(); // 合法
}
}
// 不同包非子类:不可访问
package com.example.other;
import com.example.parent.ProtectedDemo;
public class OtherClass {
public static void main(String[] args) {
ProtectedDemo demo = new ProtectedDemo();
// System.out.println(demo.protectedField); // 编译报错
}
}
3. 包访问权限(default,无修饰符)
- 可见范围:仅本类和同包类可访问,子类(不同包)和非子类不可访问。
- 适用场景:包内部的辅助类或成员,不对外暴露(如工具类的内部方法)。
package com.example.pkg;
class DefaultDemo { // 无修饰符,仅同包可见
String defaultField = "包访问属性";
void defaultMethod() {
System.out.println("包访问方法");
}
}
// 同包类:可访问
package com.example.pkg;
public class SamePackageClass {
public static void main(String[] args) {
DefaultDemo demo = new DefaultDemo();
System.out.println(demo.defaultField); // 合法
}
}
// 不同包类:不可访问
package com.example.other;
import com.example.pkg.DefaultDemo; // 编译报错(DefaultDemo 不可见)
public class OtherClass {
// 无法访问 DefaultDemo
}
4. private(私有权限)
- 可见范围:仅本类可访问,其他任何类(包括同包类和子类)均不可访问。
- 适用场景:类的内部状态(属性)或私有方法,完全隐藏实现细节(如封装中的
private属性)。
public class PrivateDemo {
private String privateField = "私有属性";
private void privateMethod() {
System.out.println("私有方法");
}
// 本类内部可访问
public void accessPrivate() {
System.out.println(privateField); // 合法
privateMethod(); // 合法
}
}
public class OtherClass {
public static void main(String[] args) {
PrivateDemo demo = new PrivateDemo();
// System.out.println(demo.privateField); // 编译报错
// demo.privateMethod(); // 编译报错
demo.accessPrivate(); // 合法(通过公共方法间接访问)
}
}
访问权限对比表
| 修饰符 | 本类 | 同包类 | 不同包子类 | 不同包非子类 |
|---|---|---|---|---|
public |
✔️ | ✔️ | ✔️ | ✔️ |
protected |
✔️ | ✔️ | ✔️ | ❌ |
| 包访问(default) | ✔️ | ✔️ | ❌ | ❌ |
private |
✔️ | ❌ | ❌ | ❌ |
使用原则与最佳实践
最小权限原则:尽可能使用小的访问权限(如能
private就不protected),减少外部依赖。属性私有化:类的属性通常用private修饰,通过public的getter/setter方法暴露必要的访问,便于添加校验逻辑。
public class User { private String name; // 私有属性 public String getName() { // 公共 getter return name; } public void setName(String name) { // 公共 setter,可添加校验 if (name == null || name.isEmpty()) { throw new IllegalArgumentException("姓名不能为空"); } this.name = name; } }接口方法公开:对外提供的接口方法用
public,内部辅助方法用private或包访问权限。谨慎使用
protected:protected成员会增加类之间的耦合,仅在需要被子类继承时使用。避免滥用
public:类的内部实现细节(如临时变量、辅助方法)不应设为public,防止外部依赖导致后续修改困难