当引用类型为 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)
在您的情况下,Q
是 a
,S
是 B
。由于 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
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)
在您的情况下,Q
是 a
,S
是 B
。由于 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