有没有办法通过反射识别Java16记录的规范构造函数?

假设我有这样的记录(或任何其他记录):

record X(int i, int j) {
    X(int i) {
        this(i, 0);
    }
    X() {
        this(0, 0);
    }
    X(String i, String j) {
        this(Integer.parseInt(i), Integer.parseInt(j));
    }
}

有没有办法通过反射找到这条记录的规范构造函数,即在RecordHeader?

回答

尝试这个

static <T extends Record> Constructor<T> canonicalConstructorOfRecord(Class<T> recordClass)
        throws NoSuchMethodException, SecurityException {
    Class<?>[] componentTypes = Arrays.stream(recordClass.getRecordComponents())
        .map(rc -> rc.getType())
        .toArray(Class<?>[]::new);
    return recordClass.getDeclaredConstructor(componentTypes);
}

Constructor<X> c = canonicalConstructorOfRecord(X.class);
X x = c.newInstance(1, 2);
System.out.println(x);

输出

X[i=1, j=2]

  • This corresponds to what is currently being considered [as an addition to the Javadoc](https://github.com/openjdk/jdk/pull/3556), following [a discussion on twitter](https://twitter.com/tagir_valeev/status/1383343671043522564), so since this will be the recommended way going forward, I'll accept this answer.
  • Nice! 2 improvements I can think of: All records extend Record, so you could prevent some runtime errors by adding a constraint to the generic type. If you do that, then `NoSuchMethodException` is effectively impossible, since all records must have a canonical constructor. So for the purpose of a convenient library method, I'd catch `NoSuchMethodException` and rethrow as a runtime exception.

回答

这似乎有效,虽然它有点蹩脚:

List<?> componentTypes = Stream
    .of(X.class.getRecordComponents())
    .map(RecordComponent::getType)
    .toList();

for (Constructor<?> c : X.class.getDeclaredConstructors())
    if (Arrays.asList(c.getParameterTypes()).equals(componentTypes))
        System.out.println(c);

印刷

Test$1X(int,int)

我仍然愿意接受更好的建议。

  • Not lame at all. Because `getRecordComponents` is guaranteed to return the components in the canonical order, and the canonical constructor is guaranteed to be there (unless an off-label compiler generates classfiles that don't adhere to the language spec), this gives you exactly what you want. The primary purpose of the reflection API is to reflect what is in the classfile; the canonical constructor of a record has no marking in the classfile, but the record components do.

以上是有没有办法通过反射识别Java16记录的规范构造函数?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>