为什么在同一个包中看不到包保护方法?

时间:2017-10-12 19:53:03

标签: java packages

假设我们有p1p2两个包,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");
    }
}

M12p2.B一起展开:

package p2;

public class B extends M12 {

    public void doSomething()  {
        method1();
        method2();
    }
} 

这会导致编译错误为method1p1内的包受保护在p2中不可见。 method2可以毫无问题地显示出来。

现在让p2.M12p1.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

我的问题是:为什么包method1中受包保护的p1在同一个包A的类p1中不可见?< / p>

3 个答案:

答案 0 :(得分:3)

我认为理解这种行为的最简单方法是“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

答案 1 :(得分:2)

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

  

一个类体可能包含该类成员的声明   是,字段(§8.3),方法(§8.4),类(§8.5)和接口   (第8.5节)。

他们是由什么组成的? JLS states

  

类类型的成员都是以下所有:

     
      
  • 直接超类(第8.1.4节)中继承的成员,但在没有直接超类的类Object中除外
  •   
  • 从任何直接超接口继承的成员(第8.1.5节)
  •   
  • 会员在课堂正文中宣布(§8.1.6)
  •   

它还提到了

  

只有声明为protectedpublic的类的成员才是   继承自在包中声明的包中声明的子类   该类被宣布。

所有这些都改编在chapter on Inheritance

  

班级C继承自直接超类所有具体方法m   (超静态和实例)所有的超类   以下是真实的:

     
      
  • mC
  • 的直接超类的成员   
  • mpublicprotected在与C` 相同的包中声明包裹访问权。
  •   
  • C中声明的方法没有签名是m签名的子签名(第8.4.2节)。
  •   

班级M1的成员是method1(以及Object的所有方法)。 M12与其直接超类M1位于不同的包中,不会继承method1。因此,M12的成员仅为method2

B的直接超类是M12,并且位于同一个包中。因此它继承了其成员method2Bmethod1一无所知。如果您使用javac编译了代码,则会收到cannot find symbol编译错误。 (似乎Eclipse试图猜测你想要做什么。)

同样,A的直接超类是M12,但是在不同的包中。由于这个原因,它不会继承method2Amethod1method2一无所知,因为它没有继承它们。这两个都是无法找到的符号。

答案 2 :(得分:1)

可见性必须流经类层次结构。

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

M1.method1以来M12不可见,它的任何子类都不可见,例如A