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

Luk*_*der 16 java reflection java-record java-16

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

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

sak*_*029 18

尝试这个

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);
}
Run Code Online (Sandbox Code Playgroud)

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

输出

X[i=1, j=2]
Run Code Online (Sandbox Code Playgroud)

  • 这对应于当前正在考虑的内容[作为 Javadoc 的补充](https://github.com/openjdk/jdk/pull/3556),遵循[twitter 上的讨论](https://twitter.com/ tagir_valeev/status/1383343671043522564),所以由于这将是今后推荐的方式,我会接受这个答案。 (3认同)
  • 好的!我能想到的 2 个改进: 所有记录都扩展 Record,因此您可以通过向泛型类型添加约束来防止一些运行时错误。如果这样做,那么“NoSuchMethodException”实际上是不可能的,因为所有记录都必须有一个规范的构造函数。因此,为了方便的库方法,我会捕获“NoSuchMethodException”并作为运行时异常重新抛出。 (2认同)

Luk*_*der 8

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

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);
Run Code Online (Sandbox Code Playgroud)

印刷

Test$1X(int,int)
Run Code Online (Sandbox Code Playgroud)

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

  • 一点也不蹩脚。因为 `getRecordComponents` 保证按规范顺序返回组件,并且保证规范构造函数存在(除非标签外编译器生成不符合语言规范的类文件),所以这正是您所需要的想。反射 API 的主要目的是反映类文件中的内容;记录的规范构造函数在类文件中没有标记,但记录组件有。 (3认同)