代码之家  ›  专栏  ›  技术社区  ›  lexicore

为什么包保护方法在同一个包中不可见?

  •  6
  • lexicore  · 技术社区  · 7 年前

    假设我们有两个包裹 p1 p2 和类 p1.M1 扩展人 p2.M12 具体如下:

    package p1;
    
    public class M1 {
        void method1() {
            System.out.println("Method 1 called");
        }
    }
    
    
    package p2;
    
    import p1.M1;
    
    public class M12 extends M1 {
        void method2() {
            System.out.println("Method 2 called");
        }
    }
    

    让我们扩展 M12 p2.B :

    package p2;
    
    public class B extends M12 {
    
        public void doSomething()  {
            method1();
            method2();
        }
    } 
    

    这会产生编译错误,如下所示: method1 ,在 p1 在中不可见 p2 . method2 清晰可见,没有问题。

    现在让我们扩展 p2.M12 p1.A :

    package p1;
    
    import p2.M12;
    
    public class A extends M12 {
    
        public void doSomething() {
            method1();
            method2();
        }
    }
    

    method2() (这是可以理解的) method1() : The method method1 from the type M1 is not visible

    哪个在包中受包保护 p1 在类中不可见 A 来自同一个包 p1 ?

    3 回复  |  直到 7 年前
        1
  •  3
  •   Sotirios Delimanolis    3 年前

    首先,什么是班级成员?这个 Java Language Specification

    类主体可以包含类成员的声明,该声明 is、字段(§8.3)、方法(§8.4)、类(§8.5)和接口 (§8.5).

    它们是由什么组成的?这个 JLS states

    类类型的成员包括以下所有成员:

    • 成员 继承 从its 直接超类 (§8.1.4),但类内对象除外,该对象没有直接超类
    • 从任何直接上级界面继承的成员(§8.1.5)
    • 成员 在类的主体中声明 (§8.1.6)

    protected public 由包中声明的子类继承,而不是 该类被声明。

    所有这些都在 chapter on Inheritance

    A类 C 继承自 所有具体方法 m (静态和实例)的所有 以下是正确的:

    • m C .
    • m 平民的 , 受保护的 在与C相同的包中声明包访问权限`
    • 中未声明方法 C 具有以下签名的子签名(§8.4.2) m .

    班级成员 M1 method1 (以及 Object ). M12 ,与它的直接超类位于不同的包中, M1 ,不继承 . 成员 M12 因此只有 method2

    B 而且在同一个包裹里。因此,它继承了其成员, 方法2 . B 对…一无所知 方法1 . 如果您使用 javac ,您将收到 cannot find symbol 而是编译错误。(Eclipse似乎在猜测您要做什么。)

    A M12 ,但在不同的包中。它不继承 方法2 A. 方法1 方法2

        2
  •  3
  •   Victor    7 年前

    我认为理解这种行为最简单的方法是“A是M12”

    当您声明继承时,您告诉A从M12获取其行为,但M12没有称为method1的可见方法。

    让我们做一个有趣的实验:

    public class M12 extends p1.M1 {
        public void method1() {
            System.out.println("Method 1 called");
        }
        void method2() {
            System.out.println("Method 2 called");
        }
    }
    

    忘记A。。当你声明这样的方法时,如果你没有@Override,它是允许的。 然而,如果M1是:

    public class M1 {
        public void method1() {
            System.out.println("Method 1 called");
        }
    }
    

    public class M12 extends p1.M1 {
        @Override
        public void method1() {
            System.out.println("Method 1 called");
        }
    
        void method2() {
            System.out.println("Method 2 called");
        }
    }
    

    现在,回到M1和M2的原始代码,重新声明方法并公开方法一:

    public class M12 extends p1.M1 {
        public void method1() {
            System.out.println("Method 1 called");
        }
    
        public void method2() {
            System.out.println("Method 2 called");
        }
    }
    

    那么,你就可以

    public class A extends M12 {
    
        public void doSomething() {
            method1();
            method2();
        }
    }
    

    好的,这是一个很小的案例,但要完成序列将丢失。。。 总之,从语义上讲,你可以用IS关系来解释。


    如果需要更多( https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html ):

    访问级别

    Modifier    Class   Package Subclass    World
    
    public      Y       Y       Y           Y
    
    protected   Y       Y       Y           N
    
    no modifier Y       Y       N           N
    
    private     Y       N       N           N
    
        3
  •  1
  •   Krease    7 年前

    可见性必须贯穿类层次结构。

    类层次结构是 A --> M12 --> M1

    M1.method1 对不可见 M12 ,它的任何子类也不可见,例如 A