为什么我不能在包外使用受保护的构造函数?
Why can't I use protected constructors outside the package?
为什么我不能在这段代码的包外使用受保护的构造函数:
package code;
public class Example{
protected Example(){}
...
}
Check.java
package test;
public class Check extends Example {
void m1() {
Example ex=new Example(); //compilation error
}
}
- 为什么我已经扩展了 class 但还是会出现错误?
请解释
编辑:
编译错误:
The constructor Example() is not visible
protected 修饰符仅在包内和包外的子classes 中使用。当您使用 Example ex=new Example();
创建对象时,默认情况下它将调用父 class 构造函数。
作为受保护的父 class 构造函数,您遇到编译时错误。您需要根据 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
}
}
事实上,您已经在使用 Example 的受保护构造函数,因为 Check 具有隐式构造函数和隐式 Example 构造函数调用:
public Check() {
super();
}
通常 protected
意味着只能被同一个包中的 sub类 或 类 访问。但是,这里是 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.
举个例子,这不编译
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) {};
}
}
所以规则很明确,但我不能说我明白背后的原因!
为什么我不能在这段代码的包外使用受保护的构造函数:
package code;
public class Example{
protected Example(){}
...
}
Check.java
package test;
public class Check extends Example {
void m1() {
Example ex=new Example(); //compilation error
}
}
- 为什么我已经扩展了 class 但还是会出现错误? 请解释
编辑:
编译错误:
The constructor Example() is not visible
protected 修饰符仅在包内和包外的子classes 中使用。当您使用 Example ex=new Example();
创建对象时,默认情况下它将调用父 class 构造函数。
作为受保护的父 class 构造函数,您遇到编译时错误。您需要根据 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
}
}
事实上,您已经在使用 Example 的受保护构造函数,因为 Check 具有隐式构造函数和隐式 Example 构造函数调用:
public Check() {
super();
}
通常 protected
意味着只能被同一个包中的 sub类 或 类 访问。但是,这里是 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.
举个例子,这不编译
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) {};
}
}
所以规则很明确,但我不能说我明白背后的原因!