为什么我们不能使用受保护的构造函数实例化一个类,如果它的子元素位于不同的包中?如果可以访问受保护的变量和方法,为什么同一规则也不适用于受保护的构造函数?
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();
}
}
答案 0 :(得分:17)
根据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
是主< / em>表达式,然后允许访问。如果访问是通过简单的类实例创建表达式
new C(...)
或限定的类实例创建表达式E.new C(...)
,那么E
是主要表达式或方法引用表达式C :: new
,其中C
是 ClassType ,则不允许访问。 A {{1构造函数可以由类实例创建表达式(不声明匿名类)或方法引用表达式访问,只能从定义它的包中访问。
在您的情况下,通过调用protected
从A
的构造函数访问B
的{{1}}受保护构造函数是合法的。但是,使用B
进行访问是不合法的。
答案 1 :(得分:9)
JLS 6.6.7回答了你的问题。子类只访问其父类的受保护成员(如果它涉及其父类的实现)。因此,如果父构造函数受到保护且它位于不同的包中,则无法在子类中实例化父对象...
6.6.7示例:受保护的字段,方法和构造函数 这个例子,里面的积分包 宣称:
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);
}
}
并且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;
}
}
定义了一个Point3d类。一个 发生编译时错误 方法delta在这里:它无法访问 受保护的成员x和y 参数p,因为Point3d (引用的类 字段x和y出现)是的子类 点(x和y所在的类) 声明),它没有参与 一个Point的实现(类型 参数p)。方法delta3d 可以访问受保护的成员 它的参数q,因为类 Point3d是Point的子类,是 参与执行 三维点。方法delta可以尝试 cast(§5.5,§15.16)其参数为 是一个Point3d,但这个演员会 失败,导致异常,如果 运行时的p类没有 三维点。
还会发生编译时错误 方法warp:它无法访问 受保护的成员z的参数a, 因为虽然班级点( 其中引用字段的类 z发生)参与了 Point3d的实现(类型 参数a),它不是 Point3d的子类(中的类) z被宣布为。)
答案 2 :(得分:4)
我同意以前的海报,不知道你为什么要这样做(在扩展课程时以这种方式实例化父母),但你甚至可以这样做:
public void test() {
A obj = new A(){}; // no compilation error; why? you use anonymous class 'override'
...
答案 3 :(得分:3)
为什么你在课堂上需要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.
}