为什么在 Java 16 中的非静态内部类中允许静态方法?

Pra*_*tet 30 java inner-classes java-16

我们知道可以使用外部类的实例访问非静态内部类,因此静态方法在非静态类中意义不大。但是从 Java 16 开始,允许在非静态内部类中使用静态方法。

为什么首先存在这个限制?为什么在较新的版本中允许这样做?

public class OuterClass {

    class InnerClass {
        static void printMe() {
            System.out.println("Inside inner class");
        }
    }

    public static void main(String[] args) {
        InnerClass.printMe();
    }

}
Run Code Online (Sandbox Code Playgroud)

And*_*eas 34

您要求对 Java 16 中的更改进行推理,因此您应该首先查看发行说明,看看它是否有什么要说的。它确实:

JEP 395:记录 ( JDK-8246771 )
工具/javac
记录已添加到 Java 语言中。记录是 Java 语言中的一种新类。它们充当不可变数据的透明载体,其仪式比普通类少。

自从嵌套类首次引入 Java 以来,除了由常量表达式初始化的静态 final 字段外,内部的嵌套类声明已被禁止声明静态成员。此限制适用于非静态成员类、本地类和匿名类。

JEP 384:Records(第二次预览)添加了对本地接口、枚举类和记录类的支持,所有这些都是静态定义。这是一个广受欢迎的增强,允许将某些声明的范围缩小到本地上下文的编码样式。

虽然JEP 384允许静态本地类和接口,但它并没有放宽对静态成员类和内部类接口的限制。内部类可以在其方法体之一中声明静态接口,但不能作为类成员声明。

作为自然的下一步,JEP 395进一步放宽了嵌套限制,并允许在内部类中声明静态类、方法、字段等。

有关更多详细信息,请参阅JEP 395

  • 有趣的是,在 C# 收到记录一年后,他们现在将记录添加到了 Java 中...... (2认同)

Ste*_*n C 22

具体的推理在JEP 395 中给出

内部类的静态成员

如果内部类声明显式或隐式静态成员,则当前指定为编译时错误,除非该成员是常量变量。这意味着,例如,内部类不能声明记录类成员,因为嵌套的记录类是隐式静态的。

我们放宽了这个限制,以允许内部类声明显式或隐式静态的成员。特别是,这允许内部类声明作为记录类的静态成员。

换句话说,有必要针对特定​​情况取消对内部类静态成员的限制;即允许record在内部类中声明类。但他们决定借此机会取消所有情况下的限制。

这意味着设计者已经得出结论,最初的限制作为一个整体既不是技术原因也不是可取的。


为什么首先存在这个限制?

这是一个更难的问题。做出这种限制的决定是在 1996 年或 1997 年初设计 Java 1.1 时做出的。任何人都不太可能仍然准确地记住最初决定背后的原因。因此,除非有人能找到同时代的书面资料,否则我们永远不会确定。

(Brian Goetz 上面评论说:*“...在添加嵌套时(Java 1.1),在另一个类中有多种可能的静态解释,所以这个问题被推迟了。”。这当然是有道理的,但这可能是(只是)一个人对大约 25 年前发生的事情的回忆。如果是我,我不会对那么远的记忆有信心。)

这里有一些关于最初限制的理由的猜测:

  • 在非静态上下文中声明的类中禁止静态可变状态(即除了常量之外没有静态字段)的一些好的动机是(1)不需要它们,因为它们等同于外部实例的字段,(2 ) 许多程序员会期望它们等同于外部类的 *static* 字段,即全局,导致混淆,(3) 静态初始化器(和带有初始化器表达式的静态字段)需要在(和每个)实例之后执行创建,而不是在类加载时只进行一次,从而使类加载器复杂化。 (3认同)