当引用类型为超类时,子类无法访问超类的受保护方法

时间:2018-02-05 13:58:25

标签: java access-modifiers

父类

package p1;

public class A {
    protected void display() {
        System.out.println("Displayed");
    }
}

子类(在另一个包中)

package p2;

import p1.A;

public class B extends A {
    public static void main(String[] args) {
        A a = new B();
        a.display();
    }
}

在子课程中,如果我写B a = new B(),它可以正常工作并显示"显示"。

但是,编写A a = new B()的子类中的上面一段代码会将编译时错误抛出为'display()' has protected access in 'p1.A'

我现在对受保护的访问修饰符感到困惑,因为当引用类型是父类时它是如何工作的?

5 个答案:

答案 0 :(得分:1)

正如我在评论中所写,你可以这样做:

package p2;

import p1.A;

public class B extends A {

    public static void main(String[] args) {
        B a = new B();
        a.foo();
    }

    public void foo() {
        display(); // works
        super.display(); // same, but more wordy
        A a = (A)this;
        a.display(); // NOT working !!!
    }

    public void bar(A a) {
        a.display(); // NOT working !!!
    }
}

display(),可以从子类调用(静态方法不是成员方法),也可以在同一个包中调用

package p1;

public class C {

    public static void main(String[] args) {
        A a = new A();
        a.display();
    }

}

嗯,那些

a.display(); // NOT working !!!

对我来说不是很清楚,请参阅discussion

答案 1 :(得分:1)

A a = new B();不起作用,因为a的引用类型为AA未将display()公开给另一个包。

举个例子:

public void method(A a){ // defined in some class in a different package
   a.display(); // can't be called from different package as reference type is `A`
}

这里的编译器无法知道您是否会分配AA的子类型,因此它会失败。

如果你忘记了你的例子并且只关注我创建的方法会更容易理解,请注意我说它是在不同包中定义的类中。现在问问自己,我可以从display()通过其他软件包调用A,显然这不是受保护的方法。

答案 2 :(得分:1)

以下是相关的语言规范段落:

  

如果访问是通过限定名称Q.Id或方法引用表达式Q :: Id(第15.13节),其中Q是ExpressionName,那么当且仅当表达式Q的类型是S或S的子类。

6.6.2.1. Access to a protected Member

在您的情况下,QaSB。由于Q的类型不是B的子类,因此不允许访问。

有关为何引入此限制的说明,请参阅Checking Access to Protected Members in the Java Virtual Machine(搜索受保护成员的要求

  

动机   对受保护访问的限制背后是防止几乎任意访问   受保护的物体成员[Yel02]。假设m是受保护的非静态的   在c中声明的字段。没有限制,任何类x都可以读取   c类任何对象的字段m的内容,使用以下技巧:定义a   c的子类(这个技巧只有在c不是最终的时才起作用,因此是“几乎”副词   以上);在s中声明一个方法,它将类c的对象作为参数和   返回其m字段的内容;并让x调用此方法。限制   受保护的访问可以防止这种情况,因为s只能访问该字段   如果对象的类o满足o≤s

答案 3 :(得分:0)

受保护的方法只能通过包外的子类继承来访问

每个子类和同一个包中的每个类都可以访问

显示

同一个软件包中的每个类都可以访问

显示(如果有不同的软件包,则不能在子类中使用)

a a = new B();将无效,因为a的引用类型为A,A不会将display()暴露给另一个包。

以下代码可以使用

package p2;

import p1.A;

public class B extends A {
    public static void main(String[] args) {
        B a = new B();
        a.demo();
    }

    public void demo(){
        display();
    }
}

答案 4 :(得分:0)

我想从链接:http://tutorials.jenkov.com/java/access-modifiers.html重要声明是

受保护的访问修饰符提供与默认访问修饰符相同的访问权限,另外子类可以访问超类的受保护方法和成员变量(字段)。

这里,子类仅表示子类引用类型。对于父引用类型,剩下的唯一选项是public。

这是一种未说明的隐藏规则。甚至IDE也建议将其更改为公开以通过父级的参考访问。怪异!