在Java中,通过反射访问私有字段是否可行?

109

在Java中,通过反射是否可以访问私有字段str?例如获取该字段的值。

class Test
{
   private String str;
   public void setStr(String value)
   {
      str = value;
   }
}

1
如果问题中包含了相关的代码以及"I tried this..."这个描述,它将会大大地得到改进。 - duffymo
这个问题是重复的 - 它已经被问过并回答了几次。 - oxbow_lakes
3个回答

195

是的,假设您具有适当的安全权限,那么它绝对可以实现。如果您从不同的类中访问该字段,请首先使用Field.setAccessible(true)

import java.lang.reflect.*;

class Other
{
    private String str;
    public void setStr(String value)
    {
        str = value;
    }
}

class Test
{
    public static void main(String[] args)
        // Just for the ease of a throwaway test. Don't
        // do this normally!
        throws Exception
    {
        Other t = new Other();
        t.setStr("hi");
        Field field = Other.class.getDeclaredField("str");
        field.setAccessible(true);
        Object value = field.get(t);
        System.out.println(value);
    }
}

不,通常情况下你不应该这样做……这是违反类的原始作者意图的。例如,在可以通常设置字段的任何情况下,可能会应用验证,或者同时更改其他字段。您实际上正在违反所期望的封装级别。


1
不错的更正。(请参阅Java编程语言安全编码准则版本2.0的指南6-4:http://java.sun.com/security/seccodeguide.html) - Tom Hawtin - tackline
14
@Downvoter: 能否解释一下为什么要点踩? - Jon Skeet
1
@JonSkeet 为什么 Java 允许这样访问私有成员?Java 为什么创建了 setAccessible() 方法? - Asif Mushtaq
1
@IslamEl-Rougy:反射通常是解决其他烦人情况的实用解决方案。如果可能的话,肯定值得避免,而且通常是一个不好的解决方案。我不知道是否会完全禁止它,但我总是会感到紧张。 - Jon Skeet
1
历史记录注释:JPMS模块在反射方面增加了更多的封装性;现在包必须至少对调用者模块开放(如果使用模块)。 - Slaw
显示剩余18条评论

56
是的。
  Field f = Test.class.getDeclaredField("str");
  f.setAccessible(true);//Very important, this allows the setting to work.
  String value = (String) f.get(object);

然后您可以使用字段对象来获取类实例上的值。

请注意,get方法经常会让人感到困惑。您有字段,但没有对象实例。您必须将其传递给get方法。


1
什么是 object - Marsellus Wallace
2
@Gevorg是一个引用变量,指向具有私有字段的类的实例。 - Yishai

5

是的,这是可能的。

您需要使用getDeclaredField方法(而不是getField方法),并提供您私有字段的名称:

Field privateField = Test.class.getDeclaredField("str");

此外,如果您想访问私有字段,还需要将此字段设置为可访问:
privateField.setAccessible(true);

完成这一步后,您可以使用Field实例上的get方法来访问str字段的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接