受保护的构造函数和可访问性
如果它的子节点位于不同的包中,为什么我们不能用受保护的构造函数实例化一个类? 如果可以访问受保护的变量和方法,为什么同一规则也不适用于受保护的构造函数?
PACK1:
package pack1; public class A { private int a; protected int b; public int c; protected A() { a = 10; b = 20; c = 30; } }
PACK2:
package pack2; import pack1.A; class B extends A { public void test() { A obj = new A(); // gives compilation error; why? //System.out.println("print private not possible :" + a); System.out.println("print protected possible :" + b); System.out.println("print public possible :" + c); } } class C { public static void main(String args[]) { A a = new A(); // gives compilation error; why? B b = new B(); b.test(); } }
根据Java Spec( https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.2 )
6.6.2.2。 对
protected
构造函数的限定访问权限设
C
是声明protected
构造函数的类,并让S
成为其声明中使用protected
构造函数的最内层类。 然后:
如果访问是通过超类构造函数调用
super(...)
或限定的超类构造函数调用E.super(...)
,其中E
是主表达式,则允许访问。如果访问是通过匿名类实例创建表达式
new C(...){...}
,或者是限定的匿名类实例创建表达式E.new C(...){...}
,其中E
是一个主表达式,然后允许访问。如果访问是通过简单的类实例创建表达式
new C(...)
,或者是限定类实例创建表达式E.new C(...)
,其中E
是主表达式,或者是方法引用表达式C :: new
,其中C
是ClassType ,然后不允许访问。protected
构造函数可以由类实例创建表达式(不声明匿名类)或方法引用表达式访问,只能从定义它的包中访问。
在您的情况下,通过调用super()
从B
构造函数访问B
受保护的构造函数是合法的。 但是,使用new
访问是不合法的。
JLS 6.6.7回答了你的问题。 子类只访问其父类的受保护成员(如果它涉及其父类的实现)。 因此,如果父构造函数受到保护且它位于不同的包中,则无法在子类中实例化父对象…
6.6.7示例:受保护的字段,方法和构造函数考虑此示例,其中points包声明:
package points; public class Point { protected int x, y; void warp(threePoint.Point3d a) { if (az > 0) // compile-time error: cannot access az a.delta(this); } }
和threePoint包声明:
package threePoint; import points.Point; public class Point3d extends Point { protected int z; public void delta(Point p) { px += this.x; // compile-time error: cannot access px py += this.y; // compile-time error: cannot access py } public void delta3d(Point3d q) { qx += this.x; qy += this.y; qz += this.z; } }
它定义了一个Point3d类。 这里的方法增量发生编译时错误:它无法访问其参数p的受保护成员x和y,因为Point3d(对x和y字段的引用出现的类)是Point的子类(声明x和y的类),它不参与Point的实现(参数p的类型)。 delta3d方法可以访问其参数q的受保护成员,因为Point3d类是Point的子类,并且参与Point3d的实现。 方法delta可以尝试将其参数(§5.5,§15.16)转换为Point3d,但如果运行时的p类不是Point3d,则此转换会失败,从而导致exception。
方法warp中也会发生编译时错误:它无法访问其参数a的受保护成员z,因为Point Point(发生字段z的引用所在的类)涉及Point3d的实现(参数a)的类型,它不是Point3d的子类(声明z的类)。
我同意以前的海报,不知道你为什么要这样做(在扩展类中以这种方式实例化父)但你甚至可以这样做:
public void test() { A obj = new A(){}; // no compilation error; why? you use anonymous class 'override' ...
为什么你需要A obj=new A();
在类中,而类b的对象本身就是class A
的对象
并且在类c中它给出错误,因为,您正在访问类A的受保护属性,它是构造函数。
要在这种情况下获取A类的对象,必须在A类中使用此函数
static A getInstance() { A obj = new A(); // create obj of type A. return obj; // returns that object by this method. No need to use 'New' kind of instantiation. }
这与受保护的字段的工作方式相同。