小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-08 / 2 阅读
0
0

Java包访问权限全面总结

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. 最佳实践和建议

访问控制策略

  1. 最小权限原则:开始使用最严格的访问权限,必要时放宽
  2. 字段尽量私有:使用getter/setter方法控制访问
  3. 包结构设计:相关功能放在同一个包中
  4. 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中包访问权限的所有重要方面,帮助你更好地理解和管理代码的可见性。


评论