为什么不能在包外部使用受保护的构造函数?

2022-09-01 04:01:09

为什么我不能在包外部为这段代码使用受保护的构造函数:

package code;
public class Example{
    protected Example(){}
    ...
}

检查.java

package test;
public class Check extends Example {
  void m1() {
     Example ex=new Example(); //compilation error
  }
}
  1. 为什么即使我已经扩展了类,我也会得到错误?请解释

编辑:

编译错误:

构造函数 Example() 不可见


答案 1

通常表示只能由同一包中的子类或类访问。但是,以下是JLS中构造函数的规则:protected

6.6.2.2. 对受保护构造函数的限定访问

设 C 是声明受保护构造函数的类,让 S 是其声明中使用受保护构造函数的最内层类。然后:

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

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

如果访问是通过简单的类实例创建表达式 new C(...) 或限定类实例创建表达式 E.new C(...),其中 E 是主表达式,或方法引用表达式 C :: new,其中 C 是 ClassType,则不允许访问。受保护的构造函数可由类实例创建表达式(不声明匿名类)或方法引用表达式从定义它的包中访问。

例如,这不会编译

public class Example extends Exception {

    void method() {
        Exception e = new Exception("Hello", null, false, false);
    }
}

但这确实

public class Example extends Exception {

    Example() {
        super("Hello", null, false, false);
    }
}

这个也是如此

public class Example {

    void method() {
        Exception e = new Exception("Hello", null, false, false) {};
    }
}

所以规则是明确的,但我不能说我理解它们背后的原因!


答案 2

受保护的修饰符仅在包中和包外部的子类中使用。使用创建对象时,默认情况下将调用父类构造函数。Example ex=new Example();

作为受保护的父类构造函数,您会收到编译时错误。您需要根据 JSL 6.6.2.2 调用受保护的构造函数,如下面的示例 2 所示。

package Super;

public class SuperConstructorCall {

    protected SuperConstructorCall() {
    }

}

package Child;

import Super.SuperConstructorCall;

public class ChildCall extends SuperConstructorCall
{

    public static void main(String[] args) {

        SuperConstructorCall s = new SuperConstructorCall(); // Compile time error saying SuperConstructorCall() has protected access in SuperConstructorCall
    }
}

符合 JLS 6.6.2.2 的示例 2

package Super;

    public class SuperConstructorCall {

    protected SuperConstructorCall() {
    }

}

package Child;

import Super.SuperConstructorCall;

public class ChildCall extends SuperConstructorCall
{

    public static void main(String[] args) {

        SuperConstructorCall s = new SuperConstructorCall(){}; // This will work as the access is by an anonymous class instance creation expression 
    }
}

推荐