Java Reflection is a process of examining the runtime behavior of a class. This feature is also known as dynamic programming since all attributes, interfaces, constructors, fields and methods of a class can be inspecting and verifying during runtime. Futhurmore, we can instantiate new objects, invoke methods, and get or set field values using reflection as well. So let’s see what is reflection and how to use it in this post.
What is Java Reflection
Java reflection is the ability for a program to manipulate the values, metadata, properties, and functions of an object at runtime.
When we creating a class in Java, it gives us an option to do introspection, which means the ability of a program to examine the type or properties of an object at runtime. A simple example of introspection is instanceof like:
1 2 3 4
Person p = new Student(); // at complie time, type of p is Person; at run time, type of p is Student! if (p instanceof Student) { p.study(); }
But introspection is only a way to kind of “check“ or “verify“ object type. Java reflection is something one step furthur: it can manipulate the object at runtime.
How to use Java Reflection
Now let’s see how to use Java Reflection API with a sample case. Here we have a Studying inferface:
1 2 3
publicinterfaceStudying{ String study(); }
then we have an abstract class Student which implement this Studying interface:
getSimpleName() will return the basic name of class, getName() and getCanonicalName() will return the fully qualified name including package name;
Class.forName("your_full_class_name") needs the full class name including package name, and it may throw ClassNotFoundException if the given class name is not found.
Class Modifiers
To inspect class modifiers like public, final, volatile, abstract, we can use class.getModifiers() which returns an int flag and pass it to Modifier.isXXX() as an argument:
getModifiers() will return an int flag which including all infos of this class’ modifier. Check the code inside java.lang.Modifier class and we can found all modifier checking is performed like (modifiers & PUBLIC) != 0 which PUBLIC is just another static int constant.
Super Class
When we have the class object, we can get the superclass by calling class.getSuperclass()
getInterfaces() will only return all interfaces directly implements by this class. In code snippt above, Master class extends Student abstract class which implements Studying interface. But only studentClass.getInterfaces() will return Studying interface even if Master class also need to implement methods of that interface. In another word, it only returns interfaces that directly declared with implements keyword.
Inspecting Constructor
Above inspection are all class-level or class-related, now let’s go to constructor. Since Java only allow single constructor with same signature in one class, we will create a Bachelor class and adding three different constructors like:
constructor.getName() will return fully qualified name including package name together;
class.getConstructor() will throw NoSuchMethodException if parameters are not matching, the order of parameters also need to be correct;
since getConstructor() will return a ? type of constructor, type casting is required to instanciate new objects, otherwise it will be Object at complie time (in this case it still will be Bachelor at runtime, but casting still required).
constructor.newInstance() will throw IllegalAccessException, InstantiationException, and InvocationTargetException. They all needs to be handled.
Inspecting Fields
For class fields, we can retrieve it, check the name, type, and even modify the value. Now let’s see how to do this.
To get all available public fields of a class or search a public field by field name, we can use getFields() or getField({field_name_string}):
@Test publicvoidgivenClassField_whenSetsAndGetsValue_thenCorrect(){ try { Class<?> bachelorClass = Class.forName("com.arctos.sample.reflection.Bachelor"); Bachelor bachelor = (Bachelor) bachelorClass.getConstructor().newInstance(); Field field = bachelorClass.getDeclaredField("graduated"); field.setAccessible(true); // set it to be accessible so we can modify it in below
assertEquals(false, field.get(bachelor)); // pass object to get() method to retrieve the value assertFalse(field.getBoolean(bachelor)); assertFalse(bachelor.isGraduated());
field.set(bachelor, true); // to set value of field, we need pass object and the new value
@Test publicvoidgivenClassField_whenGetsAndSetsWithNull_thenCorrect(){ try { Class<?> bachelorClass = Class.forName("com.arctos.sample.reflection.Bachelor"); Field field = bachelorClass.getField("GENDER"); field.setAccessible(true); // set it to be accessible so we can modify it in below
assertEquals("male", field.get(null)); // pass null as instance of class parameter
getFields() or getField({field_name_string}) will retrieve all public fields defined in the class and all superclasses;
getDeclaredFields() or getDevlaredField({field_name_string}) will retrieve all public and private fields defined in the class, nothing from superclass;
both getField({field_name_string}) and getDevlaredField({field_name_string}) will throw NoSuchFieldExceptionif given field name is wrong or not found;
field.setAccessible(true) needs to be called before modify any private field;
field.getBoolean(object) will return a boolean object but field.get(obj) will return a generic object, that’s the only difference;
for static fields, only need pass null as the instance of class parameter will be fine.
Inspecting Methods
The last thing we want to inspecting is class methods, by using Java reflection, we can retrieve all methods of a class or invoke it with parameters at runtime. So let’s start from retrieve all public methods or declared methods:
isBachelorMethod.setAccessible(true); // set it to be accessible so we can invoke it in below degreeNameMethod.setAccessible(true); // set it to be accessible so we can invoke it in below