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

Cha*_*nth 31 java constructor

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

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构造函数

让我们Cprotected声明构造函数的类中,让它S成为protected构造函数使用的声明中最内层的类.然后:

  • 如果访问是通过超类构造函数调用super(...)或限定的超类构造函数调用E.super(...)(其中E表达式),则允许访问.

  • 如果访问是通过匿名类实例创建表达式new C(...){...}或限定的匿名类实例创建表达式E.new C(...){...}(其中E表达式),则允许访问.

  • 如果通过简单的类实例创建表达式new C(...)或限定的类实例创建表达式E.new C(...)(其中E表达式或方法引用表达式C :: new,其中CClassType)进行访问,则不允许访问.protected构造可以由类实例创建表达式来访问仅在其被定义的包内(即没有声明一个匿名类)或方法参考表达.

在您的情况下,从构造函数通过调用来访问Afrom 的受保护构造函数B是合法Bsuper().但是,访问使用new不合法.


Gur*_*oca 9

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)

  • 请注意,obj 不是类“A”的(直接)实例,它是“A”的匿名子类的实例 (3认同)

Gau*_*rav 3

为什么你需要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)