Java反射-私有字段和方法

时间:2020-01-09 10:36:20  来源:igfitidea点击:

尽管大家普遍认为,实际上仍然可以通过Java Reflection访问私有字段和其他类的方法。甚至没有那么困难。在单元测试期间,这可能非常方便。此文本将向我们展示如何。

注意:这仅在将代码作为独立的Java应用程序运行时才有效,就像对单元测试和常规应用程序一样。如果尝试在Java Applet内执行此操作,则需要弄乱SecurityManager。但是,由于这不是我们经常需要执行的操作,因此到目前为止,该内容已被排除在外。

注意:关于通过Java 9的反射禁用访问私有字段的函数已有很多讨论。根据我的实验,在Java 9中似乎仍然可以实现,但是请注意,在将来的Java版本中这可能会改变。

访问私有字段

要访问私有字段,我们需要调用Class.getDeclaredField(String name)或者Class.getDeclaredFields()方法。方法Class.getField(String name)和Class.getFields()方法仅返回公共字段,因此它们将不起作用。这是一个带有私有字段的类的简单示例,下面是通过Java Reflection访问该字段的代码:

public class PrivateObject {

  private String privateString = null;

  public PrivateObject(String privateString) {
    this.privateString = privateString;
  }
}
PrivateObject privateObject = new PrivateObject("The Private Value");

Field privateStringField = PrivateObject.class.
            getDeclaredField("privateString");

privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue);

此代码示例将打印出文本" fieldValue = The Private Value",这是在代码示例开头创建的PrivateObject实例的私有字段privateString的值。

注意使用方法PrivateObject.class.getDeclaredField(" privateString")。该方法调用返回私有字段。此方法仅返回在该特定类中声明的字段,而不返回在任何超类中声明的字段。

注意行也以粗体显示。通过调用Field.setAcessible(true),我们可以关闭对此特定Field实例的访问检查,仅用于反射。现在,即使调用方不在这些范围内,我们也可以访问它,即使它是私有范围,受保护范围或者程序包范围。我们仍然无法使用常规代码访问该字段。编译器不允许这样做。

访问私有方法

要访问私有方法,我们需要调用Class.getDeclaredMethod(String name,Class [] parameterTypes)或者Class.getDeclaredMethods()方法。方法Class.getMethod(String name,Class [] parameterTypes)和Class.getMethods()方法仅返回公共方法,因此它们将不起作用。这是带有私有方法的类的简单示例,下面是通过Java Reflection访问该方法的代码:

public class PrivateObject {

  private String privateString = null;

  public PrivateObject(String privateString) {
    this.privateString = privateString;
  }

  private String getPrivateString(){
    return this.privateString;
  }
}
PrivateObject privateObject = new PrivateObject("The Private Value");

Method privateStringMethod = PrivateObject.class.
        getDeclaredMethod("getPrivateString", null);

privateStringMethod.setAccessible(true);

String returnValue = (String)
        privateStringMethod.invoke(privateObject, null);

System.out.println("returnValue = " + returnValue);

此代码示例将打印出文本" returnValue = The Private Value",这是在代码示例开头创建的" PrivateObject"实例上调用时,方法" getPrivateString()"所返回的值。

注意使用方法PrivateObject.class.getDeclaredMethod(" privateString")。正是此方法调用返回了私有方法。此方法仅返回在该特定类中声明的方法,而不返回在任何超类中声明的方法。

注意行也以粗体显示。通过调用Method.setAcessible(true),我们可以关闭此特定Method实例的访问检查,仅用于反射。现在,即使调用方不在这些范围内,我们也可以访问它,即使它是私有范围,受保护范围或者程序包范围。我们仍然无法使用常规代码访问该方法。编译器不允许这样做。