1

尽管普遍认知是,实际可以通过反射访问其他类的私有属性和方法。它甚至并不难。这个特性在单元测试中特别有用。本文将告诉你如何做。
注意:这只能在单体Java应用程序中运行,比如单元测试和常规程序。如果你尝试在Java Applet程序中使用,可能需要注意SecurityManager问题。但是,你并不常做这些操作,并且到目前为止已偏离了本文主题。
注意:已经有很多关于Java9禁用反射访问类私有属性的讨论。根据我的经历,在Java9依旧是可以的(访问类私有属性),但这可能会在Java未来版本中改变。

访问私有属性

访问私有属性需要调用Class.getDeclaredField(String name)或者Class.getDeclaredFields()方法。方法Class.getField(String name) Class.getFields()只返回类的public方法,所以不能使用它们。下面的示例代码是一个有私有属性的类,再下一个是通过反射访问私有属性。

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")时需要注意。这个方法返回私有属性。这个方法只返回特定类定义的属性,不包括任何超类的属性。
另外需要注意代码privateStringField.setAccessible(true);。调用这个方法将为特定的Field实例关闭访问权限检查,仅用于反射。现在你可以访问属性,不管它是private, protected 或者package scope,即使调用方不在访问scope内。你依旧不能使用普通代码访问私有属性,Java编译通不过。

访问私有方法

访问类私有方法需要调用Class.getDeclaredMethod(String name, Class[] parameterTypes)或者Class.getDeclaredMethods()。方法Class.getMethod(String name, Class[] parameterTypes)Class.getMethods() 只返回类的public方法,所以不能使用。下面是一个有私有方法的类和如何通过反射调用该类方法的私有代码:

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")。这个方法调用将返回类的私有方法。这个方法只返回类直接定义的方法,而不返回任何超类的方法。
另外需要注意代码privateStringMethod.setAccessible(true);。调用Method.setAcessible(true)将关闭Method实例的访问权限检查,仅用于反射。现在你可以调用方法,不论它是private, protected 或 package scope,即使调用者不在这些scopes内。你依旧不能通过普通方法访问类的私有方法,这会编译不通过。


团结
128 声望8 粉丝

诗酒趁年华