这个仔细看了jdk才发现这个问题:
jdk原话:
public void set(Object obj,
Object value)
throws IllegalArgumentException,
IllegalAccessException将指定对象变量上此 Field 对象表示的字段设置为指定的新值。如果底层字段的类型为基本类型,则对新值进行自动解包。
进行此操作的方式如下:
如果底层字段是静态字段,则忽略 obj 变量;它可能为 null。
否则底层字段是一个实例字段。如果指定对象变量为 null,则该方法将抛出一个 NullPointerException。如果指定对象变量不是声明底层字段的类或接口的实例,则该方法将抛出一个 IllegalArgumentException。
如果此 Field 对象实施 Java 语言访问控制,并且底层字段是不可访问的,则该方法将抛出一个 IllegalAccessException。
如果底层字段为 final 字段,则该方法将抛出一个 IllegalAccessException,除非 setAccessible(true) 已经继承该字段并且该字段是一个非静态字段。在通过程序的其他部分可以访问类的实例之前,只有使用空白 final 字段反序列化或重构类的实例期间,以这种方式设置 final 字段才有意义。在其他任何上下文中使用该方法都可能会有不可预知的结果,包括程序的其他部分继续使用该字段的原始值的情况。
如果底层字段的类型为某一基本类型,则可以尝试使用解包转换将新值转换为基本类型的值。如果该尝试失败,则此方法将抛出一个 IllegalArgumentException。
看到我加红的颜色了,对关键就这里。。。
如果程序改为:- package com.itheima;
- import java.lang.reflect.Field;
- public class Test {
- private final String str=null;
-
- public static void main(String[] args) throws Exception {
- Test t = new Test();
- Field field = t.getClass().getDeclaredField("str");
- field.setAccessible(true);
- field.set(t, "changed");
-
- System.out.println(field.get(t)); //此处打印 changed
-
- System.out.println(t.str); //但直接调用却打印 original
-
- Field field1 = t.getClass().getDeclaredField("str");
- System.out.println(field1.get(t));//此处还是打印 changed
- }
- }
复制代码 则会输出:
changed
changed
changed
|