【问题标题】:Why are static methods allowed inside a non-static inner class in Java 16?为什么在 Java 16 的非静态内部类中允许使用静态方法?
【发布时间】:2021-10-01 21:15:36
【问题描述】:

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

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

public class OuterClass {

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

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

}

【问题讨论】:

  • re 为什么在较新的版本中允许使用它?可能是因为它很有用。我偶尔也希望如此。封装在适当位置但不依赖任何内部或外部实例的方法似乎定义良好。
  • 一个更好的问题是:为什么这个限制首先存在?
  • @BrianGoetz 你能提供一个答案吗? :)
  • @AndyTurner 我的印象是他们想假装外部类的每个实例都有一个全新的内部类,就好像outer1.InnerClass 与outer2.InnerClass 是不同的类一样。当然,这不是它的实际工作方式,但通过禁止static,他们可以让这种错觉持续更长时间......
  • @AndyTurner user253751 的回答大部分是正确的——在添加嵌套时(Java 1.1),在另一个类中有多种可能的静态解释,所以这个问题被推迟了。

标签: java inner-classes java-16


【解决方案1】:

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

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

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

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

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

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

更多详情,请参阅JEP 395

【讨论】:

  • 有趣的是,他们现在在 Java 中添加了 Records,在 C# 收到它们一年后...
【解决方案2】:

具体推理在JEP 395中给出

内部类的静态成员

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

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

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

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


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

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

(Brian Goetz 在上面评论道:“......在添加嵌套时(Java 1.1),在另一个类中存在多种可能的静态解释,因此问题被推迟了。” em>。这当然是有道理的,但这可能是(只是)一个人对大约 25 年前发生的事情的回忆。如果是我,我不会对那么远的记忆有信心。除非我有同时代的会议纪要、笔记等可供参考。)

这里有一些关于原始限制的理由的猜测:

【讨论】:

  • 在非静态上下文中声明的类中禁止静态可变状态(即除了常量之外没有静态字段)的一些好的动机是(1)它们不是必需的,因为它们相当于外部实例的字段,(2) 许多程序员期望它们等同于外部类的 static 字段,即全局,导致混淆,(3) 静态初始化器(以及带有初始化器的静态字段表达式)将需要在创建实例之后(并且为每个实例创建)执行,而不是在加载类时只执行一次,这使类加载器复杂化。
  • 那是靠。关键是,目前负责 Java 语言的那群人显然没有被这些理由说服。
  • 是的,我只是提出一些在旧 Java 版本中可能不允许使用的原因 - 添加到您的最后一段。
猜你喜欢
  • 1970-01-01
  • 2010-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多