I was a bit puzzled when I was experimenting with GSON and noticed that it was possible to create new objects and set their private fields (member variables) even though there were no public setter methods for the private fields and there was no constructor that could be used to set them either.
When talking about it with a fellow developer he mentioned that probably Java Reflection was used.
Java Reflection can be used for a lot of things, see this comprehensive tutorial by Jakob Jenkov for a good overview. Below I will show how it can be used to set the private class members in the class below:
An you can see there are no obvious ways how to set the members privateInt and privateString. However, it can be done using Reflection. Below is a unit test that shows how this can be done:
Read the code above a couple of times to understand how it is done. The first step is to get the field using getDeclaredField, next the field is changed to accessible with the method setAccessible and finally the values are set using set.
Now, I do not recommend that you alter private members of a class, and I think it is strange that it can be done. But anyway, now you know that it can be done, and how.
When talking about it with a fellow developer he mentioned that probably Java Reflection was used.
Java Reflection can be used for a lot of things, see this comprehensive tutorial by Jakob Jenkov for a good overview. Below I will show how it can be used to set the private class members in the class below:
1: public class Privates
2: {
3: private int privateInt;
4: private String privateString;
5: public int getPrivateInt()
6: {
7: return privateInt;
8: }
9: public String getPrivateString()
10: {
11: return privateString;
12: }
13: }
An you can see there are no obvious ways how to set the members privateInt and privateString. However, it can be done using Reflection. Below is a unit test that shows how this can be done:
1: @Test
2: public void testSetPrivateField()
3: {
4: Privates privatesObj = new Privates();
5: Field privateInt;
6: Field privateString;
7: try
8: {
9: privateInt = privatesObj.getClass().getDeclaredField("privateInt");
10: privateInt.setAccessible(true);
11: privateInt.set(privatesObj, 42);
12: privateInt.setAccessible(false);
13: privateString = privatesObj.getClass().getDeclaredField("privateString");
14: privateString.setAccessible(true);
15: privateString.set(privatesObj, "The answer to life the universe and everything");
16: privateString.setAccessible(false);
17: }
18: catch (NoSuchFieldException e)
19: {
20: assertTrue(false);
21: }
22: catch (IllegalAccessException e)
23: {
24: assertTrue(false);
25: }
26: assertEquals(42, privatesObj.getPrivateInt());
27: assertEquals("The answer to life the universe and everything", privatesObj.getPrivateString());
28: }
Read the code above a couple of times to understand how it is done. The first step is to get the field using getDeclaredField, next the field is changed to accessible with the method setAccessible and finally the values are set using set.
Now, I do not recommend that you alter private members of a class, and I think it is strange that it can be done. But anyway, now you know that it can be done, and how.
Kommentarer
Skicka en kommentar