【问题标题】:Why can't I use protected constructors outside the package? [duplicate]为什么我不能在包外使用受保护的构造函数? [复制]
【发布时间】:2015-06-14 07:53:43
【问题描述】:

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

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() 不可见

【问题讨论】:

  • 了解编译错误对于诊断问题非常有用...
  • 看看这个stackoverflow.com/questions/5150748/…,你可以在子类的构造函数中使用超类的受保护构造函数,但不能在其他任何地方实例化超类实例。
  • 你不能做的原因或多或少是一样的public class Example {protected int i;} /* in another package: */ public class Check extends Example {void m1(Example ex) {ex.i = 2;}}
  • 选择重复问题是不幸的,因为这两个问题虽然相关,但截然不同,而另一个问题根本不回答这个问题。

标签: java protected access-modifiers


【解决方案1】:

protected 修饰符仅用于包内和包外的子类中。当您使用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
    }
}

示例2符合JLS 6.6.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 
    }
}

【讨论】:

  • 没有。 protected 可以跨包使用。你只需要扩展类。 default 范围是在一个包中protected 修饰符指定该成员只能在其自己的包中访问(与 package-private 一样),此外,它的类在另一个包中的子类也可以访问。
  • 答案仍然不能令人信服,我知道它会调用父类 conturtor ie> Example() 这是受保护的,但我们知道如果我们扩展该类,我们可以在包外使用受保护的修饰符那么为什么在构造函数的情况下这不起作用呢?
  • 为什么要独立调用超类的构造函数?如果超类的方法不是默认访问或私有的,则您可以直接访问它们。
【解决方案2】:

实际上你已经在使用 Example 的受保护构造函数,因为 Check 有一个隐式构造函数和隐式 Example 构造函数调用:

public Check() {
    super();
}

【讨论】:

    【解决方案3】:

    通常protected 表示只能被同一包中的子类或类访问。然而,这里是来自 JLS 的构造函数的规则:

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

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

    【讨论】:

    • 学到了新东西 ;)
    • @kittu 我也是。我没有意识到有这样奇怪的限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 2013-08-04
    • 2023-03-15
    • 2018-02-03
    • 2011-04-09
    • 2015-05-28
    相关资源
    最近更新 更多