使用子类引用访问包外的受保护成员
Posted
技术标签:
【中文标题】使用子类引用访问包外的受保护成员【英文标题】:Accessing protected members outside package with child class reference 【发布时间】:2018-10-30 05:33:14 【问题描述】:package pack1;
class A
protected void m1()
System.out.println("protected modifier");
package pack2;
class B extends A
public static void main(string[]args)
B b = new B();//Valid
b.m1();
A a = new B();//Invalid
a.m2();
A a1 = new A();//InValid
a1.m1();
为什么在访问包外的受保护成员时,我们只需要子类引用。?
为什么我们不能使用父引用来访问受保护的成员(这里 A a = new B())?
我浏览了博客和许多堆栈溢出的答案,但没有找到 WHY? 的任何答案。
那么任何人都可以帮助我知道为什么的答案吗?
【问题讨论】:
您不能访问A
,因为您仍然在子类或包之外。 main
方法是static
,因此未绑定B
类的实例。为了访问A
,您需要在 B
类中,所以在非静态上下文中。
Java : Protected access restriction for subclass on superclass object的可能重复
@Zabuza 你能详细说明你的答案吗?对我来说还不清楚
【参考方案1】:
您不能访问A
,因为您仍然在子类或包之外。 main
方法是 static
,因此与 B
类的实例未绑定。为了访问A
,您需要在 B
类中,所以在非静态上下文中,例如
public class B extends A
public void foo()
m1(); // Valid call since inside subclass
我认为你误解了static
的含义。
Java 语言规范 中描述了protected
的详细信息。摘自JLS§6.6.2:
对象的
protected
成员或构造函数只能从负责该对象的实现的代码声明的包外部访问。让
C
成为声明protected
成员的类。 仅允许在C
的子类S
的主体内访问。
限制甚至超出了您的示例。关键是“负责实施”。将其与以下示例进行比较:
package a;
public class Point
protected int x;
protected int y;
package b;
import a.Point;
public class Point3D extends Point
public void delta(Point other)
other.x += this.x; // Compile-time error: Cannot access other.x
other.y += this.y; // Compile-time error: Cannot access other.y
虽然Point3D
类是Point
的子类,但它不负责other
对象的实现。因此,不允许访问其protected
成员。
同样
public class B extends A
public void foo()
A other = new A();
other.m1(); // Compile-time error
由于foo()
方法调用所属的当前实例不负责other
的实现。因此,不允许访问。
【讨论】:
那是错误的。您的最后一次通话new A().m1();
无效,并给您一个错误:The method m1() from the type A is not visible
。您不允许从 B 访问受保护的方法 A.m1()
,除非您在 B
类型的实例上调用它。无论您是否处于静态上下文中,您都不能从 B
内部调用 new A().m1()
。
@ErwinBolwidt 这是正确的。出于与上一个示例完全相同的原因。如 JLS 段落所述,关键是“负责实施”。
@Zabuza,“Point3D 是 Point 的子类,它不负责 p 对象的实现”..如果 Point3D 不负责提供实现,那么根据你谁负责?
@sainathpawar 这是关于Point3D
的当前实例。不是班级本身。假设您有一个类Person
,那么您可以有多个实例,例如john
和jane
。而john
实例不负责jane
s 的东西。因此,不允许他访问jane
s protected
成员。只有jane
被允许这样做。而john
只对自己的protected
成员负责,所以只能访问。【参考方案2】:
继承/多态的概念使得父类的继承的公共和受保护的方法和变量——子类的成员,因此可以被子类的对象访问。受保护的访问需要两个规则-
只能被同一个包内的类访问
可以通过继承访问。
A a = 新 B();
a.m1(); //不编译
这是 B 类的一个实例,但就它是 A 的引用而言,它是一个 A 对象。这就是为什么对象“a”只能访问 A 和 B 共有的成员。即对象“a”作为类 A 的引用只能访问类 B 的继承方法。它无权访问任何B 的方法或类变量在 A 中不存在,即使它是 B 类的实例。您必须将其显式转换为 B 以使其访问 B 类的唯一方法和变量。因此,请记住这一点,就 Java 而言,对象“a”是另一个包中的类 A 对象。因此,即使方法 a.m1 被继承,“a”也无法访问它,因为它是另一个包中的 A 对象。 a.m1 将在 pack1 中编译。
与此代码对比
B b = new B();
b.m1() //compiles
b 是 B 的对象,因此适用受保护访问的规则 2。由于 m1 是对象 B 的一个继承的受保护方法,因此它可以完全访问它。
【讨论】:
以上是关于使用子类引用访问包外的受保护成员的主要内容,如果未能解决你的问题,请参考以下文章