下面這個例子在實(shí)際項(xiàng)目中一般都不會這么用,只是用來說明怎么通過反射修改類的私有字段的值.
有一個類TestData:
public class TestData {
private String name = "1";
public String getName() {
return name;
}
}
在運(yùn)行的時候怎么來修改name的值呢?
public class TestReflection extends TestCase {
public void testSetPrivateField() throws Exception {
TestData data = new TestData();
System.out.println(data.getName());
Assert.assertEquals("1", data.getName());
Field f = data.getClass().getDeclaredField("name");
f.setAccessible(true);
f.set(data, "2");
System.out.println(data.getName());
Assert.assertEquals("2", data.getName());
}
}
運(yùn)行結(jié)果:
1
2
其中,最關(guān)鍵的代碼是:
f.setAccessible(true);
這行代碼把對象data上的name字段設(shè)置為public訪問屬性.
既然私有字段可以這樣訪問,那么,類似的,私有方法也可以這樣調(diào)用!
改一下TestData:
public class TestData {
private String name = "1";
public String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
}
在TestData中增加了私有的setName方法,下面是測試代碼:
public class TestReflection extends TestCase {
public void testInvokePrivateMethod() throws Exception {
TestData data = new TestData();
System.out.println(data.getName());
Assert.assertEquals("1", data.getName());
Method m = data.getClass().getDeclaredMethod("setName", String.class);
m.setAccessible(true);
m.invoke(data, "3");
System.out.println(data.getName());
Assert.assertEquals("3", data.getName());
}
}
運(yùn)行結(jié)果:
1
3
其中最關(guān)鍵的代碼行是:
m.setAccessible(true);
它把對象data的setName方法的訪問屬性設(shè)置為public.
那么這樣調(diào)用私有方法,訪問私有屬性有什么用處呢?
在實(shí)際項(xiàng)目中,我們會使用很多其它第三方的包,有的時候是通過修改源代碼完成你想要的功能,有的時候,是因?yàn)榈谌桨袃H僅因?yàn)槟硯讉€方法的訪問屬性被設(shè)置為private,或者只要修改private的字段值即可.這個時候,用這種反射的方法就可以很容易實(shí)現(xiàn)了.
另外一個場景就是從系統(tǒng)架構(gòu)層來考慮數(shù)據(jù)封裝.例如系統(tǒng)有一些元數(shù)據(jù)類,99%的情況下,我們只是提供get方法供其它應(yīng)用層獲得字段的值,如果把修改的set方法也提供出去,那么可能會影響到系統(tǒng)的可維護(hù)性.而在系統(tǒng)運(yùn)行期間,又很難避免的要修改這些元數(shù)據(jù)的值.這種情況下,也可以通過這種反射的方式來實(shí)現(xiàn).