在我的 Java 代码中,我有一个简单的记录类,如下所示:
record SingleIndexProperties<A>(A property) implements IndexProperties {
// Here go implementations of IndexProperties methods; not relevant to question.
}
当我使用此记录运行代码的 JMH 基准测试时,我注意到最后生成的 CPU 时间火焰图中有一些有趣的东西:
请看一下jdk内部的ObjectMethods类,特别是bootstrap和makeEquals方法。
private static MethodHandle makeEquals(Class<?> receiverClass,
List<MethodHandle> getters) {
MethodType rr = MethodType.methodType(boolean.class, receiverClass, receiverClass);
MethodType ro = MethodType.methodType(boolean.class, receiverClass, Object.class);
MethodHandle instanceFalse = MethodHandles.dropArguments(FALSE, 0, receiverClass, Object.class); // (RO)Z
MethodHandle instanceTrue = MethodHandles.dropArguments(TRUE, 0, receiverClass, Object.class); // (RO)Z
MethodHandle isSameObject = OBJECT_EQ.asType(ro); // (RO)Z
MethodHandle isInstance = MethodHandles.dropArguments(CLASS_IS_INSTANCE.bindTo(receiverClass), 0, receiverClass); // (RO)Z
MethodHandle accumulator = MethodHandles.dropArguments(TRUE, 0, receiverClass, receiverClass); // (RR)Z
for (MethodHandle getter : getters) {
MethodHandle equalator = equalator(getter.type().returnType()); // (TT)Z
MethodHandle thisFieldEqual = MethodHandles.filterArguments(equalator, 0, getter, getter); // (RR)Z
accumulator = MethodHandles.guardWithTest(thisFieldEqual, accumulator, instanceFalse.asType(rr));
}
return MethodHandles.guardWithTest(isSameObject,
instanceTrue,
MethodHandles.guardWithTest(isInstance, accumulator.asType(ro), instanceFalse));
}
似乎jdk的当前实现会生成equals作为invokedynamic调用,这又会调用方法句柄组合上的许多递归调用。我希望记录类生成字节码 equals/hashcode (无论是在编译期间还是运行时),但在当前版本中似乎不是这种情况。 (当前是指截至撰写本文时的 JDK 21 和 23)
这显然对性能造成了影响。正如其他人所提到的,考虑到应用程序中其他所有内容的成本,它不太可能影响现实生活中的任何人,但如果您的分析显示了这一点,那么针对少数瓶颈类手动实现它可能是一个好主意。