-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClassAndMethodReflection.java
More file actions
144 lines (126 loc) · 5.19 KB
/
Copy pathClassAndMethodReflection.java
File metadata and controls
144 lines (126 loc) · 5.19 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package Phase6_RuntimeMemoryRegexReflection.Reflection;
import java.lang.reflect.*;
import java.util.Arrays;
/**
* Class, Method, Field — in depth
* --------------------------------
* Most useful inspection / manipulation patterns.
* <p>
*
* Finding the right method
* ------------------------
* getMethod("name", paramTypes...) - public only, includes inherited
* getDeclaredMethod("name", paramTypes...) - includes private, this class only
* getMethods() - all PUBLIC (incl. inherited)
* getDeclaredMethods() - declared here, any access
* <p>
*
* For OVERLOADED methods you must match parameter types EXACTLY.
* <p>
*
* Invocation
* ----------
* method.invoke(instance, args...)
* <p>
*
* - Static method? Pass null for instance.
* - Returns Object (boxed for primitives).
* - Wraps user exceptions in InvocationTargetException — unwrap with
* getCause().
* <p>
*
* Fields
* ------
* field.get(instance) - read
* field.set(instance, v) - write
* field.getInt(instance) - primitive variant (faster, no boxing)
* <p>
*
* - Final fields: writable via setAccessible(true) ONLY on instance
* fields, NOT on `static final` constants (the JIT may have inlined
* them).
* <p>
*
* Modifiers
* ---------
* int m = method.getModifiers();
* Modifier.isStatic(m), isFinal(m), isPublic(m), isPrivate(m), ...
* <p>
*
* Parameters (Java 8+, requires `-parameters` at compile time for names)
* ----------------------------------------------------------------------
* method.getParameters() -> Parameter[]
* parameter.getName(), .getType(), .isVarArgs()
* <p>
*
* Generic type info
* -----------------
* field.getGenericType() - includes <T>
* method.getGenericReturnType()
* method.getGenericParameterTypes()
* ParameterizedType type = (ParameterizedType) field.getGenericType();
* type.getActualTypeArguments() -> [String.class]
*/
public class ClassAndMethodReflection {
public static class Counter {
private int n;
private static int instances;
public Counter() { instances++; }
public int add(int delta) { return n += delta; }
public int add(long longDelta) { return n += (int) longDelta; } // overload
public int current() { return n; }
public static int totalInstances(){ return instances; }
}
public static void main(String[] args) throws Exception {
section("1) Find a specific overload by parameter types");
Method addInt = Counter.class.getMethod("add", int.class);
Method addLong = Counter.class.getMethod("add", long.class);
System.out.println("found: " + addInt);
System.out.println("found: " + addLong);
section("2) Invoke instance + static methods");
Counter c = Counter.class.getDeclaredConstructor().newInstance();
Object r1 = addInt.invoke(c, 5);
Object r2 = addLong.invoke(c, 10L);
System.out.println("after add(5)+add(10) = " + Counter.class.getMethod("current").invoke(c));
Object total = Counter.class.getMethod("totalInstances").invoke(null); // static
System.out.println("instances = " + total);
section("3) Field access");
Field n = Counter.class.getDeclaredField("n");
n.setAccessible(true);
System.out.println("n via reflection = " + n.getInt(c));
n.setInt(c, 100);
System.out.println("after set = " + c.current());
section("4) Modifiers");
for (Method m : Counter.class.getDeclaredMethods()) {
String mods = Modifier.toString(m.getModifiers());
System.out.println(" " + m.getName() + "(" + Arrays.toString(m.getParameterTypes()) + ") : " + mods);
}
section("5) Parameters — requires -parameters at compile time for names");
Method greet = Sample.class.getDeclaredMethod("greet", String.class, int.class);
for (Parameter p : greet.getParameters()) {
System.out.println(" " + p.getType().getSimpleName() + " " + p.getName());
}
section("6) Throw / InvocationTargetException — wrapped exceptions");
try {
Method boom = ClassAndMethodReflection.class.getDeclaredMethod("explode");
boom.invoke(null);
} catch (InvocationTargetException ite) {
System.out.println("wrapped: " + ite.getCause());
}
section("7) Generic type info");
Field samples = Sample.class.getDeclaredField("samples");
System.out.println("type = " + samples.getType().getName());
System.out.println("genericType = " + samples.getGenericType());
section("done");
}
static void explode() { throw new IllegalStateException("kaboom"); }
/** Target with a parameter name (only readable if compiled with -parameters). */
public static class Sample {
public java.util.List<String> samples;
public String greet(String name, int times) { return name + " x " + times; }
}
private static void section(String title) {
System.out.println();
System.out.println("=== " + title + " ===");
}
}