简体   繁体   English

更改记录中的字段

[英]Change field in Record

I study reflection and try to change field's value in Record.我研究反射并尝试更改 Record 中字段的值。

public record Account(Integer id, String login, Boolean blocked) {}
public class Main {
    public static void main(String[] args) {
        Account account = new Account(null, null, null);
        setFieldValue(account, "id", 1);
        setFieldValue(account, "login", "admin");
        setFieldValue(account, "blocked", false);
        System.out.println(account);
    }
    public static void setFieldValue(Object instance,
                                     String fieldName,
                                     Object value) {
        try {
            Field field = instance.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(instance, value);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

If I convert Record to Class everything works, but with Record I get Exception如果我将 Record 转换为 Class 一切正常,但是使用 Record 我得到异常

java.lang.IllegalAccessException: Can not set final java.lang.Integer field Account.id to java.lang.Integer
    at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
    at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)
    at java.base/jdk.internal.reflect.UnsafeQualifiedObjectFieldAccessorImpl.set(UnsafeQualifiedObjectFieldAccessorImpl.java:79)
    at java.base/java.lang.reflect.Field.set(Field.java:799)

What do I have to do to make the code work with records?我必须做什么才能使代码与记录一起使用?

In general the commenters saying that this "can't be done" or is "impossible" aren't wrong... unless you are willing to slightly bend the rules of the JVM:) For example, by using unsafe reflection to change the relevant value directly at the memory location in the record like this:一般来说,评论者说这“无法完成”或“不可能”并没有错......除非你愿意稍微改变 JVM 的规则:) 例如,通过使用不安全的反射来改变相关值直接在记录中的 memory 位置,如下所示:

public static void setFieldValue(Object instance, String fieldName, Object value) {
    try {
        Field f = instance.getClass().getDeclaredField(fieldName);

        Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);

        Field theInternalUnsafeField = Unsafe.class.getDeclaredField("theInternalUnsafe");
        theInternalUnsafeField.setAccessible(true);
        Object theInternalUnsafe = theInternalUnsafeField.get(null);

        Method offset = Class.forName("jdk.internal.misc.Unsafe").getMethod("objectFieldOffset", Field.class);
        unsafe.putBoolean(offset, 12, true);

        unsafe.putObject(instance, (long) offset.invoke(theInternalUnsafe, f), value);
    } catch (IllegalAccessException | NoSuchFieldException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
        e.printStackTrace();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM