Java反射-私有字段和方法
尽管大家普遍认为,实际上仍然可以通过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
实例的访问检查,仅用于反射。现在,即使调用方不在这些范围内,我们也可以访问它,即使它是私有范围,受保护范围或者程序包范围。我们仍然无法使用常规代码访问该方法。编译器不允许这样做。