如果它的子节点位于不同的包中,为什么我们不能用受保护的构造函数实例化一个类?如果可以访问受保护的变量和方法,为什么同样的规则也不适用于受保护的构造函数?
PACK1:
package pack1;
public class A {
private int a;
protected int b;
public int c;
protected A() {
a = 10;
b = 20;
c = 30;
}
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
maz*_*cha 19
根据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构造可以由类实例创建表达式来访问仅在其被定义的包内(即没有声明一个匿名类)或方法参考表达.
在您的情况下,从构造函数通过调用来访问Afrom 的受保护构造函数B是合法B的super().但是,访问使用new不合法.
JLS 6.6.7回答了你的问题.子类只访问其父类的受保护成员(如果它涉及其父类的实现).因此,如果父构造函数受到保护且它位于不同的包中,则无法在子类中实例化父对象...
6.6.7示例:受保护的字段,方法和构造函数考虑此示例,其中points包声明:
package points;
public class Point {
protected int x, y;
void warp(threePoint.Point3d a) {
if (a.z > 0) // compile-time error: cannot access a.z
a.delta(this);
}
}
Run Code Online (Sandbox Code Playgroud)
和threePoint包声明:
package threePoint;
import points.Point;
public class Point3d extends Point {
protected int z;
public void delta(Point p) {
p.x += this.x; // compile-time error: cannot access p.x
p.y += this.y; // compile-time error: cannot access p.y
}
public void delta3d(Point3d q) {
q.x += this.x;
q.y += this.y;
q.z += this.z;
}
}
Run Code Online (Sandbox Code Playgroud)
它定义了一个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,则此转换将失败,从而导致异常.
方法warp中也会发生编译时错误:它无法访问其参数a的受保护成员z,因为Point Point(发生字段z的引用所在的类)涉及Point3d的实现(参数a)的类型,它不是Point3d的子类(声明z的类).
小智 5
我同意以前的海报,不知道你为什么要这样做(在扩展类中以这种方式实例化父级)但你甚至可以做这样的事情:
public void test() {
A obj = new A(){}; // no compilation error; why? you use anonymous class 'override'
...
Run Code Online (Sandbox Code Playgroud)
为什么你需要A obj=new A();in 类,而类 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.
}
Run Code Online (Sandbox Code Playgroud)