Java包访问权限全面总结
1. 包访问权限基础
默认访问权限(包级私有)
// 包: com.example
class PackagePrivateClass { // 默认访问权限
int packageField; // 默认访问权限
void packageMethod() {} // 默认访问权限
}
访问规则表
修饰符 | 同一个类 | 同一个包 | 不同包子类 | 不同包非子类 |
---|---|---|---|---|
private | ✅ | ❌ | ❌ | ❌ |
默认 | ✅ | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ | ✅ |
2. 跨包访问场景分析
场景1:同一个包内访问
// 包: com.example
public class ClassA {
String defaultField = "可访问";
public void accessSamePackage() {
ClassB b = new ClassB(); // ✅ 可访问
String value = b.defaultField; // ✅ 可访问默认字段
b.defaultMethod(); // ✅ 可调用默认方法
}
}
class ClassB {
String defaultField = "默认字段";
void defaultMethod() {
System.out.println("默认方法");
}
}
场景2:父包访问子包
// 父包: com.company
package com.company;
import com.company.sub.ChildClass;
public class ParentPackageClass {
public void accessChildPackage() {
ChildClass child = new ChildClass(); // ✅ 仅当ChildClass为public
child.publicMethod(); // ✅ 可访问public方法
// child.defaultMethod(); // ❌ 不能访问默认方法
}
}
// 子包: com.company.sub
package com.company.sub;
public class ChildClass {
public void publicMethod() {}
void defaultMethod() {} // 父包无法访问
}
场景3:子包访问父包
// 子包: com.company.sub
package com.company.sub;
import com.company.ParentClass;
public class ChildPackageClass {
public void accessParentPackage() {
ParentClass parent = new ParentClass(); // ✅ 仅当ParentClass为public
parent.publicMethod(); // ✅ 可访问public方法
// parent.defaultMethod(); // ❌ 不能访问默认方法
}
}
场景4:无关系的不同包
// 包: com.packageA
package com.packageA;
public class ClassA {
public void publicMethod() {}
protected void protectedMethod() {}
void defaultMethod() {}
}
// 包: com.packageB
package com.packageB;
import com.packageA.ClassA;
public class ClassB {
public void testAccess() {
ClassA a = new ClassA();
a.publicMethod(); // ✅ 可访问
// a.protectedMethod(); // ❌ 不能访问(非子类)
// a.defaultMethod(); // ❌ 不能访问
}
}
3. 继承中的跨包访问
跨包继承访问protected成员
// 包: com.base
package com.base;
public class BaseClass {
protected String protectedField = "protected字段";
public String publicField = "public字段";
protected void protectedMethod() {
System.out.println("protected方法");
}
}
// 包: com.derived
package com.derived;
import com.base.BaseClass;
public class DerivedClass extends BaseClass {
public void accessProtected() {
// ✅ 在子类中可以直接访问protected成员
System.out.println(protectedField);
protectedMethod();
// ✅ 通过子类实例访问
DerivedClass derived = new DerivedClass();
System.out.println(derived.protectedField);
derived.protectedMethod();
// ❌ 不能通过父类实例访问
BaseClass base = new BaseClass();
// System.out.println(base.protectedField); // 编译错误
// base.protectedMethod(); // 编译错误
}
}
4. 静态成员的跨包访问
// 包: com.utils
package com.utils;
public class MathUtils {
public static final double PI = 3.14159;
protected static int protectedCounter = 0;
static int packageCounter = 0; // 默认权限
public static int add(int a, int b) {
return a + b;
}
}
// 包: com.client
package com.client;
import com.utils.MathUtils;
import static com.utils.MathUtils.PI; // 静态导入
public class Calculator {
public void calculate() {
double area = PI * 10 * 10; // ✅ 通过静态导入
double area2 = MathUtils.PI * 10 * 10; // ✅ 通过类名访问
int result = MathUtils.add(5, 3); // ✅ 访问public静态方法
// ❌ 以下访问都不允许
// MathUtils.protectedCounter++;
// MathUtils.packageCounter++;
}
}
5. 内部类的包访问权限
// 包: com.outer
package com.outer;
public class OuterClass {
private String privateField = "private";
String packageField = "package";
// public内部类 - 跨包可访问
public class PublicInner {
public void access() {
System.out.println(privateField); // ✅ 可访问外部类私有成员
System.out.println(packageField); // ✅ 可访问包级成员
}
}
// 默认权限内部类 - 仅同包可访问
class PackageInner {
void access() {
System.out.println("同包可访问");
}
}
}
// 另一个包中使用
package com.another;
import com.outer.OuterClass;
public class AnotherPackageClass {
public void test() {
OuterClass outer = new OuterClass();
OuterClass.PublicInner inner = outer.new PublicInner(); // ✅ 可访问
// OuterClass.PackageInner packageInner = outer.new PackageInner(); // ❌ 编译错误
}
}
6. 接口的包访问权限
// 包: com.interfaces
package com.interfaces;
public interface PublicInterface {
void publicMethod();
// 接口方法默认public,字段默认public static final
String CONSTANT = "常量";
}
interface PackageInterface { // 默认权限,仅同包可访问
void packageMethod();
}
// 包: com.implementations
package com.implementations;
import com.interfaces.PublicInterface;
public class Implementation implements PublicInterface {
public void publicMethod() { // 必须为public
System.out.println("实现方法");
}
// ❌ 不能实现PackageInterface,因为不可见
// public class PackageImpl implements PackageInterface {}
}
7. 枚举的包访问权限
// 包: com.enums
package com.enums;
public enum PublicEnum {
VALUE1, VALUE2, VALUE3;
public void publicMethod() {}
void packageMethod() {} // 仅同包可访问
}
enum PackageEnum { // 默认权限,仅同包可访问
ITEM1, ITEM2;
}
// 包: com.client
package com.client;
import com.enums.PublicEnum;
public class EnumClient {
public void useEnum() {
PublicEnum value = PublicEnum.VALUE1; // ✅ 可访问
value.publicMethod(); // ✅ 可调用public方法
// value.packageMethod(); // ❌ 不能调用默认方法
// ❌ 不能访问PackageEnum
// PackageEnum item = PackageEnum.ITEM1;
}
}
8. 最佳实践和建议
访问控制策略
- 最小权限原则:开始使用最严格的访问权限,必要时放宽
- 字段尽量私有:使用getter/setter方法控制访问
- 包结构设计:相关功能放在同一个包中
- API设计:public接口要稳定,protected用于扩展点
常见模式
// 使用工厂方法控制对象创建
public class ServiceFactory {
static Service createService() {
return new DefaultService(); // DefaultService可以是包级私有
}
// 包级私有的实现类
static class DefaultService implements Service {
public void execute() {
// 实现细节
}
}
}
public interface Service {
void execute();
}
这个全面的总结涵盖了Java中包访问权限的所有重要方面,帮助你更好地理解和管理代码的可见性。