关于java:为什么我不能在包外使用受保护的构造函数?

Why can't I use protected constructors outside the package?

本问题已经有最佳答案,请猛点这里访问。

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

1
2
3
4
5
package code;
public class Example{
    protected Example(){}
    ...
}

JAVA

1
2
3
4
5
6
package test;
public class Check extends Example {
  void m1() {
     Example ex=new Example(); //compilation error
  }
}
  • 即使我已经扩展了类,为什么我会得到错误?请解释
  • 编辑:

    编译错误:

    The constructor Example() is not visible


    通常,protected意味着只能访问同一包中的子类或类。但是,以下是jls中的建设者规则:

    6.6.2.2. Qualified Access to a protected Constructor

    Let C be the class in which a protected constructor is declared and
    let S be the innermost class in whose declaration the use of the
    protected constructor occurs. Then:

    If the access is by a superclass constructor invocation super(...),
    or a qualified superclass constructor invocation E.super(...), where E
    is a Primary expression, then the access is permitted.

    If the access is by an anonymous class instance creation expression
    new C(...){...}, or a qualified anonymous class instance creation
    expression E.new C(...){...}, where E is a Primary expression, then
    the access is permitted.

    If the access is by a simple class instance creation expression new
    C(...), or a qualified class instance creation expression E.new
    C(...), where E is a Primary expression, or a method reference
    expression C :: new, where C is a ClassType, then the access is not
    permitted. A protected constructor can be accessed by a class instance
    creation expression (that does not declare an anonymous class) or a
    method reference expression only from within the package in which it
    is defined.

    作为一个例子,这不会编译

    1
    2
    3
    4
    5
    6
    public class Example extends Exception {

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

    但这确实

    1
    2
    3
    4
    5
    6
    public class Example extends Exception {

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

    这个也是

    1
    2
    3
    4
    5
    6
    public class Example {

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

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


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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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
        }
    }

    实施例2符合JLS 6.6.2.2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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
        }
    }


    实际上,您已经在使用示例的受保护构造函数,因为check具有隐式构造函数和隐式示例构造函数调用:

    1
    2
    3
    public Check() {
        super();
    }