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

时间:2011-03-01 05:13:14

标签: 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;
    }
}

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();
    }
}

4 个答案:

答案 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构造函数可以由类实例创建表达式(不声明匿名类)或方法引用表达式访问,只能从定义它的包中访问。

  •   

在您的情况下,通过调用protectedA的构造函数访问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.
}