当前位置: 首页 > 面试题库 >

私有内部类的默认构造函数是否具有形式参数?

许俊风
2023-03-14
问题内容

警告#1:实际上这是一个潜在的两部分:首先,私有内部类的构造函数是否具有形式参数?如果是,为什么JLS拒绝呢?如果没有,怎么/为什么不呢?

注意事项2: 此问题不用于推测。 我仅在寻找 权威 答案。

默认构造函数在JLS
8.8.9
中定义,该声明(部分说明):

除了在 非私有
内部成员类中之外,默认构造函数没有形式参数,在默认情况下,默认构造函数隐式声明一个表示该类的立即封闭实例的形式参数(第8.8.1节,第15.9.2节,第15.9.3节)
)。

(添加了重点)

“非私有”位对我来说似乎很奇怪:为了让内部类访问其封闭类中定义的字段,它需要对该实例的引用。无论内部类是否为私有,都应相同。

实际上,与规范相反,javac似乎同意我的观点。如果我编译此:

public class Ctors {
  private class MyInner {
  }
}

…并运行javap -c -private,然后我们看到一个带有单个形式参数的构造函数,用于封闭类的实例:

$ javap -c -private Ctors\$MyInner
Compiled from "Ctors.java"
class Ctors$MyInner {
  final Ctors this$0;

  private Ctors$MyInner(Ctors);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1        // Field this$0:LCtors;
       5: aload_0
       6: invokespecial #2        // Method java/lang/Object."<init>":()V
       9: return
}

作为参考,它在Oracle JDK 1.8.0_05上。

因此,JLS说私有内部成员类的默认构造函数没有形式参数,而javac /
javap说它有一个。(我对最自然的工作方式的理解也会说,它应该有一种,但值得的。)哪个是对的,为什么JLS专门排除私有内部类?


问题答案:

实现和规范之间有区别。

我认为“除外” JLS声明

除了 非私有内部成员类…

措辞不佳。

这意味着, 不需要 编译器隐式声明一个表示该类的立即封闭实例的形式参数…但是 可以

为什么非私有内部成员类 需要 隐式形式参数?

从JLS
8.8.1开始

成员类可能是由与类实例创建表达式的编译器不同的编译器发出的。因此,创建表达式的编译器必须有一种标准方法将引用(表示立即封闭的实例)传递给成员类的构造函数

例如,如果我使用第一个编译器编译此内部类:

package p1;
public class Ctors {
    public class MyInner {
    }
}

如果我想用另一个编译器编译这个子类:

package p2;

import p1.Ctors;

public class SubCtors {
    public SubCtors() {
        new Ctors();
    }
}

第二个编译器必须能够将默认构造函数与形式参数一起使用。在这种情况下,带有一个SubCtors实例的封闭类的实例。

为什么在非私有内部成员类中 不需要 隐式形式参数?

因为非私有内部成员类始终由编译它的同一编译器访问。如您所示,无论类可见性如何,javac都会生成相同的构造函数,但这不是必需的。另一个编译器实现可以自由选择其他方式。

JLS
8.8.1还有一点,就是同一条线

在用于 本地类(不是在静态上下文中)
或匿名类的类实例创建表达式中,第15.9.2节指定了本地/匿名类的直接封闭实例。本地/匿名类必须由与类实例创建表达式相同的编译器发出。该编译器可以随心所欲地表示立即封闭的实例。
Java编程语言无需在本地/匿名类的构造函数中隐式声明参数。



 类似资料:
  • 我正在重构一个越来越大的android项目。运行lint使我能够在外部类和内部类之间访问JSME问题私有成员。考虑下面的例子 我得到消息了 应用问题解决方案会将源更改为 我现在有点困惑。直到现在,我还以为这个例子相当于 在这种情况下,我错了吗?还是这是棉绒的问题?

  • 问题内容: 以下是两种方法: 具有所有类属性的构造函数 优点:我必须输入确切数量的参数类型,所以如果出现错误,编译器会警告我(顺便说一句,有什么方法可以防止错误地在参数列表中切换两个Integer的问题?) 缺点:如果我有很多属性,则实例化行可能会变得很长,并且可能跨越两行或更多行 setter和默认的空构造函数 优点:我可以清楚地看到自己的设置,因此,如果我做错了什么,我可以在键入时立即查明它(

  • 问题内容: 我不想为我的班级创建默认的构造函数。 但是Spring似乎坚持: 这真的有必要吗? 问题答案: 你是如何定义bean的?听起来你可能已经告诉Spring实例化你的bean,例如以下之一: 没有提供构造函数参数的地方。前一个将使用默认(或不使用arg)构造函数。如果要使用接受参数的构造函数,则需要使用如下元素来指定它们: 如果你想在你的应用程序上下文引用另一个bean中,你可以使用它做的

  • 问题内容: 我有一堂课。 在我的类方法中,我实例化该类,如下所示: 编译器将此代码转换为: 使用反射表明该类具有以下综合的构造函数: 由于该类是,因此编译器会将该构造函数添加到该类中,因此没有人可以实例化该类。但是很明显,该类应该能够实例化它,因此编译器添加了另一个包私有构造函数,后者又调用了私有构造函数。另外,由于package- private构造函数的名称中包含该名称,因此普通的Java代码

  • 问题内容: 如果父类中有带参数的构造函数,为什么需要默认构造函数(显式) 这将是一个错误。 问题答案: 这里有两个方面的工作: 如果 确实 明确指定了构造函数(如中所述),则Java编译器将 不会 为您创建无参数构造函数。 如果您未明确指定构造函数(如所示),则Java编译器将为您创建一个无参数的构造函数,如下所示: (可访问性取决于类本身的可访问性。) 试图调用超类无参数构造函数-因此它必须存在