Java:如何确定初始化程序块中定义的本地类是否需要封闭实例进行实例化?

dam*_*ewl 11 java reflection static class

现在我正在实现一个方法,它有一个Class类型的参数,如果给定的类对象需要一个实例来封闭它来实例化它,那么这个方法返回一个布尔值.

该方法目前的工作原理如下:

    if (clazz.getEnclosingClass() == null) {
        return false;
    }
    if (clazz.isAnonymousClass() || clazz.isMemberClass()) {
        return !Modifier.isStatic(clazz.getModifiers());
    }
    if (clazz.getEnclosingConstructor() != null) {
        return true;
    }
    final Method enclosingMethod = clazz.getEnclosingMethod();
    if (enclosingMethod != null) {
        return !Modifier.isStatic(enclosingMethod.getModifiers());
    }
Run Code Online (Sandbox Code Playgroud)

解释为什么这样设计:

  1. 它首先检查它是否是顶级类,如果是,算法可以安全地返回false
  2. 如果该类是匿名的或成员类,如果它不是静态的,则它需要一个关闭实例(如果在静态构造函数/ method/initializer-block中声明了anynmous类,则它是自动静态的)
  3. 现在可以假定该类是本地类(忽略数组和基元),因此它在构造函数,方法或初始化程序中定义.但是,与匿名类不同,本地类从不被视为静态类,但如果在非静态块中定义本地类,则仍需要封闭实例.
  4. 构造函数永远不会是静态的,因此在这种情况下返回true
  5. 如果它在方法中定义,则如果方法不是静态的,则返回true

我需要步骤6来确定本地类是驻留在静态初始化块还是实例初始化块中,所以我已完成此函数的实现.

所以这里的反射API有点短.没有方法Class.getEnclosingInitializer()等,也没有一个类代表反射包中的初始化器.

初始化程序块不是类的成员吗?在java 1.8规范中,Member接口只有实现类Field,Executable(带有子类Constructor和Method),然后有大多数反射用户的成员名称.

我不确定规范背后的人是否忘记了这种情况,如果在静态方法/初始化程序(如匿名类)中声明,本地类实际应该是静态的.但在我看来,从这个角度来看,它缺乏最后的一致性.

那么有没有人知道如何确定本地类声明在哪种类型的初始化程序块中?

我并不是真的热衷于挖掘一个类似于它的封闭类的合成类型的字段,或者循环它的构造函数以获得类似于它的东西(旁注:参数对象Constructor.getParameters()始终返回false isImplicit()isSynthetic()不管我尝试什么. ......那似乎是错的).所以如果我能避免这样的解决方案那么好.

apa*_*gin 2

一个有趣的谜题,但恐怕没有满足您要求的解决方案。一旦源文件被编译成字节码,有关类封闭范围的详细信息就会丢失。请记住,JVM 不仅仅适用于 Java 语言,而所描述的问题大多是特定于语言的。

\n\n
\n\n
\n

我需要步骤 6 来确定本地类是否驻留在静态初始化程序块或实例初始化程序块中

\n
\n\n

在运行时没有此类信息可用。类文件具有EnclosingMethod本地或匿名类的属性(JVMS \xc2\xa74.7.7 )。但是,无法区分封闭实例初始值设定项和静态初始值设定项。规范明确指出

\n\n

如果当前类立即通过实例初始值设定项、静态初始值设定项、实例变量初始值设定项或类变量初始值设定项\xc2\xbb 包含在源代码中,\xc2\xabmethod_index 必须为零

\n\n

考虑以下两种情况:

\n\n
class Outer {\n    {\n        // Local class inside instance initializer\n        class Local {}\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
class Outer {\n    static {\n        // Local class inside static initializer\n        class Local {\n            final Outer this$0;\n\n            Local(Outer outer) {\n                this$0 = outer;\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

它们被编译为几乎相同的类文件。唯一的区别是该字段在第一种情况下this$0有标志,但在第二种情况下没有。SYNTHETIC但检查这个标志正是您想要避免的。(为什么?)

\n\n
\n\n
\n

如果在静态方法/初始化程序中声明,本地类实际上应该是静态的(如匿名类)

\n
\n\n

我认为本地类和匿名类都不应该是静态的。此外,Java 语言规范要求它们是非静态的:

\n\n
    \n
  • 修饰符 static 仅适用于成员类,不适用于顶级类、本地类或匿名类( JLS \xc2\xa78.1.1 )。
  • \n
  • 匿名类始终是内部类;它永远不是静态的JLS \xc2\xa715.9.5)。
  • \n
\n\n

因此,这显然是getModifiers()有时会返回STATIC匿名类的规范违规。即将推出的 JDK 9 中已修复了一个错误JDK-8034044。这会破坏算法的第 2 步。

\n\n
\n\n

好吧,那该怎么办呢?这取决于你的实际意思

\n\n
\n

如果给定的类对象需要它的封闭类的实例\n 才能对其进行实例化

\n
\n\n

我想说,上面的定义意味着类的所有构造函数都有一个封闭类类型的额外参数。在这种情况下,如果没有封闭类的实例,确实无法实例化类。

\n\n

但是,如果您确实希望区分初始值设定项和静态初始值设定项,那么您唯一的机会(如我上面所示)是查找带有SYNTHETIC标志的字段。

\n