父类
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'
我现在对受保护的访问修饰符感到困惑,因为当引用类型是父类时它是如何工作的?
答案 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
的引用类型为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
的子类型,因此它会失败。
如果你忘记了你的例子并且只关注我创建的方法会更容易理解,请注意我说它是在不同包中定义的类中。现在问问自己,我可以从display()
通过其他软件包调用A
,显然这不是受保护的方法。
答案 2 :(得分:1)
以下是相关的语言规范段落:
如果访问是通过限定名称Q.Id或方法引用表达式Q :: Id(第15.13节),其中Q是ExpressionName,那么当且仅当表达式Q的类型是S或S的子类。
(6.6.2.1. Access to a protected Member)
在您的情况下,Q
为a
,S
为B
。由于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也建议将其更改为公开以通过父级的参考访问。怪异!