Define Data Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.util.HashMap;
import java.util.List;

public class Person {
public String country;
public String city;
private String name;
private int age;
private final String finalValue;
private final String inlineFinalValue = "inline-final";
private static String staticValue = "static";

public Person(){
finalValue = "final";
System.out.println("Executed no args constructor");
}

private Person(String country, String city, String name){
finalValue = "final";
this.country = country;
this.city = city;
this.name = name;
System.out.println("Executed private constructor!");
}

private String getMobile(int dummy){
System.out.println("getMobile() method invoked!");
System.out.println("The argument is " + dummy);
return "123456";
}

public static String getStaticValue(){
return staticValue;
}

public void genericTypeTest(HashMap<String, Person> map, List<String> list){

}

public void setAge(int age){
if (age < 0 || age > 100){
System.out.println("Invalid Age!");
}else{
this.age = age;
}
}

public int getAge(){
return age;
}
@Override
public String toString() {
return String.format("Person: [Country: %s, City: %s, Name: %s, Age: %d, Final: %s, static: %s, Inline-final: %s]",
country, city, name, age, finalValue, staticValue, inlineFinalValue);
}
}

Test Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

public class Main {
public static void main(String[] args){
try {
Class<?> clazz = Class.forName("Person");
// Get public constructors
Constructor[] constructors = clazz.getConstructors();
System.out.println("\nPublic constructors\n");
printIterable(Arrays.asList(constructors));
Constructor constructor = clazz.getConstructor();
Person person = (Person) constructor.newInstance();
System.out.println(person);

// Get all constructors
Constructor[] allConstructors = clazz.getDeclaredConstructors();
System.out.println("\nAll constructors:\n");
printIterable(Arrays.asList(allConstructors));
Constructor constructor1 = clazz.getDeclaredConstructor(String.class, String.class, String.class);
constructor1.setAccessible(true);
person = (Person) constructor1.newInstance("China", "GuangDong", "Peng-YM");
System.out.println(constructor1.getModifiers());
System.out.println(person);

// Get public fields
System.out.println("\nPublic fields\n");
Field[] fields = clazz.getFields();
printIterable(Arrays.asList(fields));

// Get all fields
System.out.println("\nAll fields\n");
Field[] allFields = clazz.getDeclaredFields();
printIterable(Arrays.asList(allFields));

// Get specific field
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);

// Cannot modify it to an invalid value with public method
person.setAge(-1);
System.out.println(person);

// But we can modify it with reflection
age.setInt(person, -1);
System.out.println(person);

// Get final field
Field finalField = clazz.getDeclaredField("finalValue");
finalField.setAccessible(true);

// Cannot modify final value by this
finalField.set(person, "modified-final");
System.out.println(person);

// You should first remove the final modifier then you can modify it
Field modifierField = Field.class.getDeclaredField("modifiers");
modifierField.setAccessible(true);
modifierField.setInt(finalField, finalField.getModifiers() & ~Modifier.FINAL);

finalField.set(person, "modified-final");
System.out.println(person);

// With this technique, we can even modify a private field to public
modifierField.setInt(finalField, Modifier.PUBLIC);
// But still cannot do this since reflection happens in running time
// System.out.println("Now public: " + person.finalValue);

// However, inline final value is compile-time constant hence cannot be modified
Field inlineFinal = clazz.getDeclaredField("inlineFinalValue");
inlineFinal.setAccessible(true);
modifierField.setInt(inlineFinal, inlineFinal.getModifiers() & ~Modifier.FINAL);
inlineFinal.set(person, "modified-inline-final");
System.out.println(person); // nothing happens

// Modify static value
Field staticField = clazz.getDeclaredField("staticValue");
staticField.setAccessible(true);
staticField.set(person, "modified-static");
System.out.println(person);

// Get public methods
System.out.println("\nPublic methods\n");
Method[] methods = clazz.getMethods();
printIterable(Arrays.asList(methods));

// Get all methods
System.out.println("\nAll Methods\n");
Method[] allMethods = clazz.getMethods();
printIterable(Arrays.asList(allMethods));

// Execute method
Method getMobile = clazz.getDeclaredMethod("getMobile", int.class);
getMobile.setAccessible(true);
getMobile.invoke(person, 123);

// Execute class method
Method classMethod = clazz.getDeclaredMethod("getStaticValue");
System.out.println("\nThe static value is: " + classMethod.invoke(person));

// Get generic type
Method genericMethod = clazz.getDeclaredMethod("genericTypeTest", HashMap.class, List.class);
Type[] genericParameterTypes = genericMethod.getGenericParameterTypes();
System.out.println("\nGeneric Types");
printIterable(Arrays.asList(genericParameterTypes));
ParameterizedType parameterizedType = (ParameterizedType) genericParameterTypes[0];
System.out.println("\nRaw Type: " + parameterizedType.getRawType());
Type[] actualTypes = parameterizedType.getActualTypeArguments();
System.out.println("\nActual Types:\n");
printIterable(Arrays.asList(actualTypes));

} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchFieldException e) {
e.printStackTrace();
}
}

private static void printIterable(Collection<?> iterable){
for (Object i: iterable){
System.out.println(i);
}
}
}