Introduction
Reflection, as we know from the common term, is an image of yourself or something else you see in a mirror or a mirrored surface. Java, being an object-oriented language draws heavily from real-life examples and so is the Reflection API of Java inspired from real life.
Table of Contents
In Java, the process of analyzing, viewing and modifying all the internal attributes, behaviors and capabilities of a class at runtime is called Reflection. Using the concept of Reflection, a programmer can now manipulate all attributes of a class – including its methods, constructors, and fields even at runtime, and even invoke methods of that class and get a complete snapshot of it.
Reflection is heavily used in Java frameworks such as Spring, Hibernate, Junit etc.
The ‘reflect’ package
The core collection of classes and information related to Reflection in Java is encapsulated as the java.lang.reflect package. It contains several interfaces and classes which define methods that are used for reflection of other classes.
Let us have a look at some of the classes within the java.lang.reflect package
Field
This class provides information about the fields present in the class whose reflection is being looked at.
Modifier
This class provides information about the class and other members’ access modifiers of the class being reflected.
Proxy
This class supports the dynamic proxy classes
Method
This class provides information about the methods of the class being reflected and inspected.
Constructor
This class provides information regarding the constructors of the class being reflected and inspected.
Array
This class allows the programmer to dynamically create and manipulate Arrays
Other than these, the java.lang.Class class is one of the most important classes in use for Reflection as the objects of Class can store the actual information of the class that we want to investigate or reflect.
Uses of Reflection in Java
Extensibility
Using the concepts of reflection, a programmer can make use of externally available user-defined classes by creating instances of those extensible objects by using their fully qualified name
Developing IDEs and Class Browsers
IDEs, especially those which are capable of visual development, such as Eclipse or Netbeans, and class browsers can make extensive use of Reflection. Using these, the visual development environments make the information of the classes readily available to the user so that they can write proper code.
Debugging and Testing tools
Debugging requires the ability to view internal details of a class which include its private members.Debugging and Testing tools may use reflection to make systematic invocations to the classes by use of reflection and ensure test case coverage.
Disadvantages of Reflection
Inspite of being an extremely powerful tool, Reflection API and its usage does have a set of disadvantages such as,
Low Performace
The use of reflection API can lead to high performance overhead and lead to lower performance. This is because many functionalities make use of dynamic resolution which prevents to the use of certain Virtual machine optimisations. As it tends to slow down processing, it isn’t recommended for use in sections of code that require high availability and low turnaround.
Security Risk
Reflection API requires cetain security permissions that are not available during execution under a securely managed system. Also, the security permission requirements can pose a threat to code residing in a secure system.
Exposure of Internal Fields and Attributes
Due to the ability of Reflection API to access private members and invoke private functions, the internal details of classes and entities are exposed to the outside world and defeats the purpose of Abstraction in object oriented concepts, which may be seen as a violation of object oriented programming concepts.
Now that we have had an overview of the basic idea of Reflection, let us go through the java.lang.Class class which plays the most significant role in reflection in java.
Java.lang.Class – the gateway to Reflection
The Class is a final class in the java.lang package of Java’s standard library, and extends the Object class which forms the basis of all classes in java. An instance of the class Class is used to represent both classes and interfaces in a Java application which is running. Using an instance of Class, we can view, analyse and modify the attributes of a class while it is running, and can even invoke methods of that class.
Important Methods of java.lang.Class
The Class class has a wide variety of methods that are useful in obtaining a reflection of the class executing and performing a wide range of actions with that class. Some of these methods are:
forName() method:
This method accepts the full qualified name of a class or an interface as an argument and returns an instance of the class associated with the qualifed name, including all its attributes and behaviours.
The syntax for the forName method is as follows:
1 2 3 |
static Class<?> forName(String className) |
Let us see an example of the forName method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class TestClass{} class ReflectionTest { public static void main(String args[]) { Class c = null; try { c = Class.forName("TestClass"); } catch (ClassNotFoundException e) { System.out.println(e.getMessage()); } System.out.println(c.getName()); } } |
The above code generates the following output:
getConstructors() and getDeclaredConstructors() methods:
The getConstructors() method returns an array of the declared public constructors of the invoking object in the form of java.lang.reflect.Constructor objects. The getDeclaredConstructors() method returns all the constructors of the invoking object including non-public members.
The syntax for both getConstructors() and getDeclaredConstructors() are as follows:
1 2 3 4 |
Constructor< ?>[] getConstructors(); Constructor< ?>[] getDeclaredConstructors(); |
Let us see an example of the use of the above methods:
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 |
package org.arpit.java2blog; import java.lang.reflect.Constructor; class TestClass{ public TestClass(){} protected TestClass(Integer a){} } public class ReflectionTest { public static void main(String args[]) { try { Class c = Class.forName("org.arpit.java2blog.TestClass"); System.out.println("Using getConstructors()"); Constructor< TestClass>[] ct = c.getConstructors(); for(int i=0; i< ct.length; i++) { System.out.println(ct[i]); } System.out.println("===================="); System.out.println("Using getDeclaredConstructors()"); Constructor< TestClass>[] cdt = c.getDeclaredConstructors(); for(int i=0;i< cdt.length;i++) { System.out.println(cdt[i]);} } catch(Exception e) { e.printStackTrace();} } } |
The above code on execution produces the following output:
public org.arpit.java2blog.TestClass()
====================
Using getDeclaredConstructors()
public org.arpit.java2blog.TestClass()
protected org.arpit.java2blog.TestClass(java.lang.Integer)
getMethods() and getDeclaredMethods()
The getMethods() function of java.lang.Class returns an array of java.lang.reflect.Method instances that reflect and return all the public methods of the invoking object. On the other hand, the getDeclaredMethods() function returns only the methods declared by the programmer.
The syntax for both functions are as follows:
1 2 3 4 |
Method< ?>[] getMethods(); Method< ?>[] getDeclaredMethods(); |
Let us see an example of the use of the above methods:
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 |
package org.arpit.java2blog; import java.lang.reflect.Method; class TestClass { public void put() { } protected int show() { return 1; } } public class ReflectionTest { public static void main(String args[]) { try { Class c = Class.forName("org.arpit.java2blog.TestClass"); Method mr[] = c.getMethods(); System.out.println("=================="); System.out.println("Using getMethods()"); System.out.println("=================="); for (int i = 0; i < mr.length; i++) { System.out.println(mr[i]); } Method md[] = c.getDeclaredMethods(); System.out.println("==========================="); System.out.println("Using getDeclaredMethods()"); System.out.println("============================"); for (int i = 0; i < md.length; i++) { System.out.println(md[i]); } } catch (Exception e) { e.printStackTrace(); } } } |
The above code on execution produces the following result:
Using getMethods()
==================
public void org.arpit.java2blog.TestClass2.put()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
===========================
Using getDeclaredMethods()
============================
public void org.arpit.java2blog.TestClass2.put()
protected int org.arpit.java2blog.TestClass2.show()
Thus you can see that the getMethods() method returns all the public methods of the object including superclasses, whereas getDeclaredMethods() only returned user-declared methods.
getFields() and getDeclaredFields() methods:
The getFields() methods returns an array consisting of java.lang.Field objects which display all the public attributes of the invoking class or interface. On the other hand, the getDeclaredFields() method returns an array of Field objects which represent all the fields declkared in the invoking class or interface.
The syntax of the methods are as follows:
1 2 3 4 |
Field< ?>[] getFields(); Field< ?>[] getDeclaredFields(); |
Let us see an example of the above methods:
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 |
package org.arpit.java2blog; import java.lang.reflect.Field; class TestClass { public int a; String b; } public class ReflectionTest { public static void main(String args[]) { try { Class c = Class.forName("org.arpit.java2blog.TestClass"); Field ff[] = c.getFields(); System.out.println("Using getFields() method"); System.out.println("======================="); for (int i = 0; i < ff.length; i++) { System.out.println(ff[i]); } Field f[] = c.getDeclaredFields(); System.out.println("======================="); System.out.println("Using getDeclaredFields() method"); System.out.println("======================="); for (int i = 0; i < f.length; i++) { System.out.println(f[i]); } } catch (Exception e) { e.printStackTrace(); } } } |
The above code produces the following result on execution.
=======================
public int org.arpit.java2blog.TestClass.a
=======================
Using getDeclaredFields() method
=======================
public int org.arpit.java2blog.TestClass.a
java.lang.String org.arpit.java2blog.TestClass.b
Conclusion
Java’s greatest positives is that the design of Java was made such as to encapsulate a diversely dynamic environment – Classes are loaded dynamically, methods are bound dynamically, variables are created dynamically. This led to the idea of manipulating the classes and viewing them dynamically which materialized as the Reflection API of Java. Reflection helps to make Java a dynamic language that further enhances the benefits of the language.