繁体   English   中英

尝试在运行时使用反射更改属性的值会导致 NullPointerException

[英]Trying to change the value of a property at runtime using reflection results in NullPointerException

我有一个 class 正在编写单元测试:

import java.io.File;

public class MyLogger {

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

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

我想从另一个 class 中更改分配给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)

问题在于set方法的第一个参数。 它需要您尝试修改以执行更改的 object 的实例。 现在,您所做的类似于尝试执行null.logFile = newValue ,这显然会失败。

您需要向setFinal方法添加另一个参数,并将logger变量传递给它以用作该参数。

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

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

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

private static void setFinal(Field field, Object toModify, 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(toModify, newValue);
}

您以错误的方式使用Field.set方法。 您需要提供必须设置新字段值的object ,在您的代码中它应该是logger object 但您传递的是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的方法签名:

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

我可以使用 java.lang.reflect.Method 来做到这一点,检查下面的代码是否有助于解决您的问题。

Method method = MyLogger.getClass().getDeclaredMethod("getLogFile");
            method.setAccessible(true);

在 getDeclaredMethod 中,您需要提供完整的方法名称。

暂无
暂无

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

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