当引用类型为 super-class 时,Sub-class 无法访问 super-class 的受保护方法

Sub-class not able to access the protected method of super-class when the reference is of type super-class

Parent class

package p1;

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

Child class(在另一个包中)

package p2;

import p1.A;

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

在childclass中,如果我写B a = new B(),它工作正常并显示"Displayed"。

但是,在 child class 中写了 A a = new B() 的上面一段代码,它会抛出编译时错误 'display()' has protected access in 'p1.A'

我现在对受保护的访问修饰符感到困惑,因为当引用类型为 parent?

时它是如何工作的

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

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

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

display 将可供同一包中的每个子class 和每个 class 访问。

display 将可供同一包中的每个 class 访问(儿童不可用 class 如果有不同的包)

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();
    }
}

A a = new B(); 不起作用,因为 a 的引用类型是 A 并且 A 不会将 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`
}

此处的编译器无法知道您将分配 A 还是 A 的子类型,因此它会退出。

如果您暂时忘记您的示例并只关注我创建的方法,将会更容易理解,请注意我说的是在另一个包中定义的 class 中。现在问问自己,我可以从不同的包中调用 A 上的 display() 吗,显然它不是受保护的方法。

我认为来自link:http://tutorials.jenkov.com/java/access-modifiers.html重要的声明是

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

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

这是一种不言而喻的潜规则。甚至 IDE 也建议将其更改为 public 以通过父引用访问。奇怪!

这里是相关的语言规范段落:

If the access is by a qualified name Q.Id or a method reference expression Q :: Id (§15.13), where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S.

(6.6.2.1. Access to a protected Member)

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

有关引入此限制的原因的解释,请参阅检查对受保护成员的访问 在 Java 虚拟机 中(搜索 受保护成员的要求

The motivation behind the restriction on protected access is to prevent almost arbitrary access to protected members of objects [Yel02]. Suppose that m is a protected, nonstatic field declared in c. Without the restriction, any class x could read the content of the field m of any object of class c, using the following trick: define a subclass s of c (the trick works only if c is not final, hence the “almost” adverb above); declare a method in s that takes an object of class c as argument and returns the content of its m field; and have x call this method. The restriction on protected access prevents this situation, because s can access the field only if the class o of the object satisfies o ≤ s