受保护的构造函数和可访问性

如果它的子节点位于不同的包中,为什么我们不能用受保护的构造函数实例化一个类? 如果可以访问受保护的变量和方法,为什么同一规则也不适用于受保护的构造函数?

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 ,其中CClassType ,然后不允许访问。 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. } 

这与受保护的字段的工作方式相同。