首页 > 解决方案 > 尝试在运行时使用反射更改属性的值会导致 NullPointerException

问题描述

我有一门课要写单元测试:

import java.io.File;

public class MyLogger {

    private final File logFile = new File("default");

    public File getLogFile() {
        return this.logFile;
    }
}

我想logFile从另一个类中更改分配给的值,例如:

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Main {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, Exception {

        MyLogger logger = new MyLogger();
        System.out.println(logger.getLogFile());

        setFinal(MyLogger.class.getDeclaredField("logFile"), new File("changed"));
        System.out.println(logger.getLogFile());
    }

    private static void setFinal(Field field, Object newValue) throws Exception {
        field.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.set(null, newValue);
    }
}

但我得到以下输出/异常:

default
Exception in thread "main" java.lang.NullPointerException
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:57)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
    at java.lang.reflect.Field.set(Field.java:764)
    at Main.setFinal(Main.java:23)
    at Main.main(Main.java:12)

标签: javareflection

解决方案


Field.set以错误的方式使用该方法。您需要提供必须设置新字段值的对象,在您的代码中它应该是logger对象,但您正在传递null

public static void main(String[] args) throws NoSuchFieldException, SecurityException, Exception {

    MyLogger logger = new MyLogger();
    System.out.println(logger.getLogFile());

    setFinal(logger, MyLogger.class.getDeclaredField("logFile"), new File("changed"));
    System.out.println(logger.getLogFile());
}

private static void setFinal(MyLogger logger, Field field, Object newValue) throws Exception {
    field.setAccessible(true);

    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

    field.set(logger, newValue);
}

这是根据文档中的Field.set方法签名

将指定对象参数上的此 Field 对象表示的字段设置为指定的新值。


推荐阅读