根据反射,为什么 DirectMethodHandle$Holder 不是 DirectMethodHandle 的成员类?

Lai*_*son 3 java reflection annotation-processing

考虑一下DirectMethodHandle$Holder班级。(它是 所返回的类之一Class.forName("java.lang.invoke.DirectMethodHandle").getDeclaredClasses(),记录为返回成员类。)

以下断言在 JDK 19 下失败:

assert Class.forName("java.lang.invoke.DirectMethodHandle$Holder").isMemberClass();
Run Code Online (Sandbox Code Playgroud)

为什么?它违反了第 8.5 条的哪条规则?

和一些评论者一样,我得出的结论是,这是一个非常奇怪的错误。例如,使用某些javax.annotation.processing和某些javax.lang.model.*类,以下断言不会失败:

assert NestingKind.MEMBER == ((TypeElement)processingEnvironment.getElementUtils().getTypeElement("java.lang.invoke.DirectMethodHandle.Holder")).getNestingKind();
Run Code Online (Sandbox Code Playgroud)

因此,支持编译器的机制的输出与反射机制的输出不一致。我已经针对 JDK 提交了一个错误

Hol*_*ger 5

请记住,您正在查看用于 Java/JVM 交互的非常特殊的代码。查看源代码之前的注释时,您会得到提示:

\n
/* Placeholder class for DirectMethodHandles generated ahead of time */\nfinal class Holder {}\n
Run Code Online (Sandbox Code Playgroud)\n

强调 \xe2\x80\x9cplaceholder\xe2\x80\x9d 和 \xe2\x80\x9c generated\xe2\x80\x9d

\n

当我运行时jdk-17\\bin\\javap java.lang.invoke.DirectMethodHandle$Holder,我得到以下输出:

\n
final class java.lang.invoke.DirectMethodHandle$Holder {\n  static int invokeInterface(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, int);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, long);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static void invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, double);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, int, int);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, int, java.lang.Object);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, int);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, int);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, int);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, long);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, long, long);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, java.lang.Object, java.lang.Object, java.lang.Object);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, java.lang.Object, int, java.lang.Object);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, java.lang.Object, int);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, java.lang.Object, long, java.lang.Object);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, java.lang.Object, long);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, java.lang.Object, java.lang.Object);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long, java.lang.Object);\n  static long invokeSpecial(java.lang.Object, java.lang.Object, long);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object, long);\n  static int invokeSpecial(java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeSpecial(java.lang.Object, java.lang.Object);\n  static void invokeSpecial(java.lang.Object, java.lang.Object);\n  static int invokeSpecialIFC(java.lang.Object, java.lang.Object, java.lang.Object, int);\n  static int invokeSpecialIFC(java.lang.Object, java.lang.Object, int);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, double, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, double);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, int, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, int);\n  static int invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, long);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static void invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, double);\n  static int invokeStatic(java.lang.Object, int, int, int);\n  static int invokeStatic(java.lang.Object, int, int);\n  static int invokeStatic(java.lang.Object, int);\n  static java.lang.Object invokeStatic(java.lang.Object, int);\n  static long invokeStatic(java.lang.Object, long, int);\n  static long invokeStatic(java.lang.Object, long, long);\n  static long invokeStatic(java.lang.Object, long, java.lang.Object, java.lang.Object, java.lang.Object);\n  static long invokeStatic(java.lang.Object, long, java.lang.Object, int, java.lang.Object);\n  static long invokeStatic(java.lang.Object, long, java.lang.Object, long, java.lang.Object);\n  static long invokeStatic(java.lang.Object, long, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, long);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object, long);\n  static int invokeStatic(java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeStatic(java.lang.Object);\n  static void invokeStatic(java.lang.Object);\n  static java.lang.Object invokeStaticInit(java.lang.Object, java.lang.Object);\n  static void invokeVirtual(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object invokeVirtual(java.lang.Object, java.lang.Object);\n  static java.lang.Object newInvokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object newInvokeSpecial(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object newInvokeSpecial(java.lang.Object, int, int);\n  static java.lang.Object newInvokeSpecial(java.lang.Object, int);\n  static java.lang.Object newInvokeSpecial(java.lang.Object, java.lang.Object);\n  static java.lang.Object newInvokeSpecial(java.lang.Object);\n  static int getBoolean(java.lang.Object, java.lang.Object);\n  static int getBooleanVolatile(java.lang.Object, java.lang.Object);\n  static void putBoolean(java.lang.Object, java.lang.Object, int);\n  static void putBooleanVolatile(java.lang.Object, java.lang.Object, int);\n  static int getBoolean(java.lang.Object);\n  static int getBooleanVolatile(java.lang.Object);\n  static void putBoolean(java.lang.Object, int);\n  static void putBooleanVolatile(java.lang.Object, int);\n  static int getByte(java.lang.Object, java.lang.Object);\n  static int getByteVolatile(java.lang.Object, java.lang.Object);\n  static void putByte(java.lang.Object, java.lang.Object, int);\n  static void putByteVolatile(java.lang.Object, java.lang.Object, int);\n  static int getByte(java.lang.Object);\n  static int getByteVolatile(java.lang.Object);\n  static void putByte(java.lang.Object, int);\n  static void putByteVolatile(java.lang.Object, int);\n  static int getShort(java.lang.Object, java.lang.Object);\n  static int getShortVolatile(java.lang.Object, java.lang.Object);\n  static void putShort(java.lang.Object, java.lang.Object, int);\n  static void putShortVolatile(java.lang.Object, java.lang.Object, int);\n  static int getShort(java.lang.Object);\n  static int getShortVolatile(java.lang.Object);\n  static void putShort(java.lang.Object, int);\n  static void putShortVolatile(java.lang.Object, int);\n  static int getChar(java.lang.Object, java.lang.Object);\n  static int getCharVolatile(java.lang.Object, java.lang.Object);\n  static void putChar(java.lang.Object, java.lang.Object, int);\n  static void putCharVolatile(java.lang.Object, java.lang.Object, int);\n  static int getChar(java.lang.Object);\n  static int getCharVolatile(java.lang.Object);\n  static void putChar(java.lang.Object, int);\n  static void putCharVolatile(java.lang.Object, int);\n  static int getInt(java.lang.Object, java.lang.Object);\n  static int getIntVolatile(java.lang.Object, java.lang.Object);\n  static void putInt(java.lang.Object, java.lang.Object, int);\n  static void putIntVolatile(java.lang.Object, java.lang.Object, int);\n  static int getInt(java.lang.Object);\n  static int getIntVolatile(java.lang.Object);\n  static void putInt(java.lang.Object, int);\n  static void putIntVolatile(java.lang.Object, int);\n  static long getLong(java.lang.Object, java.lang.Object);\n  static long getLongVolatile(java.lang.Object, java.lang.Object);\n  static void putLong(java.lang.Object, java.lang.Object, long);\n  static void putLongVolatile(java.lang.Object, java.lang.Object, long);\n  static long getLong(java.lang.Object);\n  static long getLongVolatile(java.lang.Object);\n  static void putLong(java.lang.Object, long);\n  static void putLongVolatile(java.lang.Object, long);\n  static float getFloat(java.lang.Object, java.lang.Object);\n  static float getFloatVolatile(java.lang.Object, java.lang.Object);\n  static void putFloat(java.lang.Object, java.lang.Object, float);\n  static void putFloatVolatile(java.lang.Object, java.lang.Object, float);\n  static float getFloat(java.lang.Object);\n  static float getFloatVolatile(java.lang.Object);\n  static void putFloat(java.lang.Object, float);\n  static void putFloatVolatile(java.lang.Object, float);\n  static double getDouble(java.lang.Object, java.lang.Object);\n  static double getDoubleVolatile(java.lang.Object, java.lang.Object);\n  static void putDouble(java.lang.Object, java.lang.Object, double);\n  static void putDoubleVolatile(java.lang.Object, java.lang.Object, double);\n  static double getDouble(java.lang.Object);\n  static double getDoubleVolatile(java.lang.Object);\n  static void putDouble(java.lang.Object, double);\n  static void putDoubleVolatile(java.lang.Object, double);\n  static java.lang.Object getReference(java.lang.Object, java.lang.Object);\n  static java.lang.Object getReferenceVolatile(java.lang.Object, java.lang.Object);\n  static void putReference(java.lang.Object, java.lang.Object, java.lang.Object);\n  static void putReferenceVolatile(java.lang.Object, java.lang.Object, java.lang.Object);\n  static java.lang.Object getReference(java.lang.Object);\n  static java.lang.Object getReferenceVolatile(java.lang.Object);\n  static void putReference(java.lang.Object, java.lang.Object);\n  static void putReferenceVolatile(java.lang.Object, java.lang.Object);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是一个强烈的暗示,表明该类不是通过编译空的单行定义获得的类。看来这个实际类文件的生成器并不关心为替换类文件生成等效InnerClasses属性。由于此属性对代码的实际执行没有影响,因此\xe2\x80\x99 应该无关紧要。

\n

因此,\xe2\x80\x99s 没有错误,无论是在编译器中还是在反射中,不匹配是由于该类并非源自源代码这一事实引起的。

\n

  • 反射仅告诉您它在类文件中找到了什么。如前所述,类文件在源代码编译和 JDK 部署之间的某个时刻已被替换。这里没问题,因为一开始就不需要内部类。它不用作内部类。顾名思义,它只是一个占位符。以及实施细节。 (2认同)