Java:通过反射访问私有字段(行为)

3

Java初学者;使用反射可以访问私有字段(不问如何访问,参见问题1问题2)。

我的问题与此行为的性质有关。

  1. 是否存在任何限制?我能访问遇到的任何.class的任何字段吗?
  2. 在我的代码中,一旦将字段的可见性设置为例如"public",它会永久改变还是仅在上下文结构(方法, if, for…)结束之前有效?请查看以下代码
  3. 对所有人来说这样做是否安全?我的意思是,StackOverflow的高级程序员们,这是否是一种安全漏洞?

代码 [已编辑]:

  Field f = obj.getClass().getDeclaredField("field"); 
  if (...) {
     f.setAccessible(true);
     // f IS accesible
  }
  // is f accesible?

1
有一些情况下,反射是一种违规行为。其中一个我想到的情况是通过反射访问Singleton类的私有构造函数来创建多个实例。 - Chetan Kinger
3
如果您提到的是 f.setAccessible(true),那么您正在授予对该特定 Field 实例所表示的字段的访问权限。如果您创建另一个实例的 Field 指向同一字段(无论之前是否对先前的 Field 实例调用了 setAccessible(true)),则此新实例将无法访问私有字段。在您的代码中,如果设置字段的可见性为 "public",则与 setAccessible(true) 不同,它将永久地公开该字段而不仅仅是在特定实例上。 - Pshemo
@Chetan Kinger 没错!如果某个东西被设计为私有的...就让它保持私有。在私有属性的情况下...尝试调用相关的getter方法。Pshemo,在上下文的末尾,你调用setAccessible之后它还是可访问的吗(编辑我的问题)? - Manu Artero
1
@manutero 这样的限制将必须由类的开发人员强制执行。在Singleton示例的情况下,可以通过在构造函数中抛出异常来实现,如果指向类实例的自引用不为null。当使用反射的调用者收到此异常时,应推断该类是单例,并寻找其他获取类实例句柄的方法。 - Chetan Kinger
1
有时候我们希望能够直接设置一些私有值,而不是通过setter方法来设置,例如当我们测试代码的错误值时(这些值通常无法通过良好编写的setter方法来设置)。 - Pshemo
1个回答

3

是否有限制?

是的 - 为了使其起作用,您需要几个JVM权限(其中最重要的是accessDeclaredMemberssuppressAccessChecks,在文档中用大而粗的警告标记),如果您的JVM安全配置文件相对严格(比如广受诟病的小应用程序),那么您的代码将无法正常工作,因为这些权限将不可用。

它会永久改变吗?

会的,只要您的程序继续运行,这些字段就会保持可访问状态(只要您继续使用相同的更改了访问权限的 Field 实例)。

这是坏事吗?

不一定。它允许Java代码序列化和反序列化具有私有字段的对象,它允许复杂的模拟,可能简化测试,它允许您窥视您否则无法窥视的地方。但是,由于它打破了预期,您应该谨慎使用,并确保用户知道您需要额外的权限并且“正在查看内部运作”。文档(见上文)非常清楚地说明,这被认为是有风险的,并且只有在您知道自己在做什么时才允许使用。


“它会永久改变吗?是的,只要您的程序继续运行,这些字段将保持可访问状态。” 这仅适用于通过调用“setAccessible(true)”的Field实例访问此字段(并且没有抛出SecurityException)。 我们仍然无法直接访问私有字段(不使用反射)。 - Pshemo

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