A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 原满 中级黑马   /  2013-6-1 14:59  /  3027 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 原满 于 2013-6-1 15:04 编辑

public class Test {
    private final String str = "original";
     
    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
original
changed

想不太明白原因  求指点{:soso_e100:}

评分

参与人数 1技术分 +1 收起 理由
殇_心。 + 1

查看全部评分

4 个回复

倒序浏览
求大神指教。。。

我是这么认为的,t 是一个对象,field 也是一个对象,field对象封装了 t 对象的一个字段 str.

field.set(t, "changed"); 这句代码只是修改了field对象中str 的值,而没有修改 t 对象中str 的值。 不知道对不对。

回复 使用道具 举报
对与Java中的final变量,java编译器是进行了优化的。
System.out.println(t.str); 所以这里被编译器优化了, 字节码里已经是“original”的字节码了,而不是System.out.println(t.str)的字节码。(这里楼主思考下)
所以编译阶段已经出结果了。
其他两个的话,都是运行时分析,所以得出的是正确的结果。

评分

参与人数 1技术分 +1 收起 理由
殇_心。 + 1

查看全部评分

回复 使用道具 举报
这个仔细看了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。

看到我加红的颜色了,对关键就这里。。。

如果程序改为:
  1. package com.itheima;

  2. import java.lang.reflect.Field;

  3. public class Test {
  4.     private final String str=null;
  5.      
  6.     public static void main(String[] args) throws Exception {
  7.         Test t = new Test();
  8.         Field field = t.getClass().getDeclaredField("str");
  9.         field.setAccessible(true);
  10.         field.set(t, "changed");
  11.          
  12.         System.out.println(field.get(t)); //此处打印  changed
  13.          
  14.         System.out.println(t.str); //但直接调用却打印   original
  15.          
  16.         Field field1 = t.getClass().getDeclaredField("str");
  17.         System.out.println(field1.get(t));//此处还是打印  changed
  18.     }
  19. }
复制代码
则会输出:
changed
changed
changed

评分

参与人数 1技术分 +1 收起 理由
殇_心。 + 1

查看全部评分

回复 使用道具 举报
如果问题已解决,请及时修改分类,否则继续提问,谢谢合作!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马