reflection

Java Reflection Example

Java Reflection API provides the ability to inspect and modify the runtime behavior of applications. Using reflection we can inspect a class or an interface, get their constructors, methods, and fields information at runtime even though the class is not accessible at compile time. We can also use reflection to instantiate an object, invoke it’s methods, change field values. The classes of Reflection API are part of the package java.lang.reflect and the methods of Reflection API are parts of the package java.lang.Class.

1. Introduction

Before we use the capabilities offered by Reflection API, we must first obtain the java.lang.Class object of the class. If we know the name of the class at compile time, we can do the following:

Class object = classObject.class;

After the creation of the class object, we can use any method of the java.lang.Class package according to our needs.

2. Technologies used

The example code in this article was built and run using:

  • Java 1.8.231(1.8.x will do fine)
  • Eclipse IDE for Enterprise Java Developers-Photon

3. Common Methods

3.1 Common methods of java.lang.Class

what is reflection in java
  • String getName()
    Returns the full name of the entity represented by this Class object, as a String.
  • String getSimpleName()
    Returns the simple name of the underlying class as given in the source code.
  • Package getPackage()
    Gets the package for this class.
  • Constructor<T>[] getConstructors()
    Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object.
  • Constructor<T> getConstructor(Class<?>... parameterTypes)
    Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object.
  • Method[] getDeclaredMethods()
    Returns an array of Method objects reflecting all the methods declared by the class or interface represented by this Class object.
  • Method[] getMethods()
    Returns an array containing Method objects reflecting all the public member methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from super-classes and super-interfaces.
  • Field[] getFields()
    Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object.
  • Field getField(String name)
    Returns a Field object that reflects the specified public member field of the class or interface represented by this Class object.

For further information, you can have a look at java.lang.Class API.

3.2 Common methods of java.lang.reflect.Constructor

Using Java Reflection API we can inspect the constructors of classes and instantiate objects at runtime. The obtaining of constructor object is achieved by the perspective methods of the class java.lang.reflect.Constructor.
Specifically, for the instantiation of an object we use the following method:

  • AnnotatedType getAnnotatedReceiverType​()
    Returns an AnnotatedType object that represents the use of a type to specify the receiver type of the method/constructor represented by this Executable object.
  • AnnotatedType getAnnotatedReturnType​()
    Returns an AnnotatedType object that represents the use of a type to specify the return type of the method/constructor represented by this Executable.
  • <T extends Annotation> T getAnnotation​(Class<T> annotationClass)
    Returns this element’s annotation for the specified type if such an annotation is present, else null.
  • Annotation[] getDeclaredAnnotations()
    Returns all annotations that are directly present on this element.
  • Annotation[][] getParameterAnnotations()
    Returns an array of arrays that represent the annotations on the formal parameters, in declaration order, of the method represented by this Method object.
  • Class<T> getDeclaringClass()
    Returns the Class object representing the class that declares the constructor represented by this object.
  • String getName​()
    Returns the name of this constructor, as a string.
  • TypeVariable<Constructor<T>>[] getTypeParameters​()
    Returns an array of TypeVariable objects that represent the type variables declared by the generic declaration represented by this GenericDeclaration object, in declaration order.
  • void setAccessible​(boolean flag)
    Set the accessible flag for this reflected object to the indicated boolean value.
  • T newInstance(Object... args)
    Uses the constructor represented by this Constructor object to create and initialize a new instance of the constructor’s declaring class, with the specified initialization parameters.
  • boolean equals(Object obj)
    Compares this Method against the specified object.
  • Type[] getGenericExceptionTypes()
    Returns an array of Type objects that represent the exceptions declared to be thrown by this Constructor object.
  • Type[] getGenericParameterTypes()
    Returns an array of Type objects that represent the formal parameter types, in declaration order, of the method represented by this Constructor object.
  • int hashCode()
    Returns a hashcode for this Constructor.
  • boolean isSynthetic()
    Returns true if this method is a synthetic method; returns false otherwise.
  • boolean isVarArgs()
    Returns true if this method was declared to take a variable number of arguments; returns false otherwise.
  • String toGenericString()
    Returns a string describing this Method, including type parameters.
  • String toString()
    Returns a string describing this Method.

For further information, you can have a look at java.lang.reflect.Constructor API.

3.3 Common methods of java.lang.reflect.Method

Using Java Reflection API we can inspect the methods of classes and invoke them at runtime. This is achieved by using the Java class java.lang.reflect.Method.

  • String getName()
    Returns the name of the method represented by this Method object, as a String.
  • Class[] getParameterTypes()
    Returns an array of Class objects that represent the formal parameter types, in declaration order, of the method represented by this Method object.
  • Class getReturnType()
    Returns a Class object that represents the formal return type of the method represented by this Method object.
  • Object invoke(Object obj, Object... args)
    Invokes the underlying method represented by this Method object, on the specified object with the specified parameters.
  • int getParameterCount()
    Returns the number of formal parameters (whether explicitly declared or implicitly declared or neither) for the executable represented by this object.
  • Type getGenericReturnType()
    Returns a Type object that represents the formal return type of the method represented by this Method object.
  • Object getDefaultValue()
    Returns the default value for the annotation member represented by this Method instance.
  • Type getGenericReturnType()
    Returns a Type object that represents the formal return type of the method represented by this Method object.
  • boolean isDefault()
    Returns true if this method is a default method; returns false otherwise.
  • boolean isBridge()
    Returns true if this method is a bridge method; returns false otherwise.

For further information, you can have a look at java.lang.reflect.Method API.

3.4 Common methods of java.lang.reflect.Field

Using Java Reflection API we can inspect the fields (member variables) of classes at runtime. This is achieved by using the java class java.lang.reflect.Field .

  • String getName()
    Returns the name of the field represented by this Field object.
  • Class<?> getType()
    Returns a Class object that identifies the declared type for the field represented by this Field object.
  • Object get(Object obj)
    Returns the value of the field represented by this Field, on the specified object.
  • boolean isEnumConstant()
    Returns true if this field represents an element of an enumerated type; returns false otherwise.
  • Object get(Object obj)
    Returns the value of the field represented by this Field, on the specified object.

For further information, you can have a look at java.lang.reflect.Field API.

3.5 Common methods of java.lang.reflect.Array

The Array class cannot be instantiated and exports static methods to create Java arrays with primitive or class component types, and to get and set array component values.

  • Object get(Object array, int index)
    Returns the value of the indexed component of the specified array object.
  • Object newInstance(Class componentType, int length or dimensions)
    Returns a new array with the specified component type and length or dimensions.
  • int getLength(Object array)
    Returns the length of the specified array.
  • boolean getBoolean(Object array, int index)
    Returns the value of the indexed element in the specified array object, as a boolean.
  • byte getByte(Object array, int index)
    Returns the value of the indexed element in the specified array object, as a byte.
  • char getChar(Object array, int index)
    Returns the value of the indexed element in the specified array object, as a char.
  • short getShort(Object array, int index)
    Returns the value of the indexed element in the specified array object, as a short.
  • int getInt(Object array, int index)
    Returns the value of the indexed element in the specified array object, as an int.
  • long getLong(Object array, int index)
    Returns the value of the indexed element in the specified array object, as a long.
  • float getFloat(Object array, int index)
    Returns the value of the indexed element in the specified array object, as a float.
  • double getDouble(Object array, int index)
    Returns the value of the indexed element in the specified array object, as a double.
  • set(Object array, int index, Object value)
    Sets the indexed component of the specified array object to the specified new value.
  • setBoolean(Object array, int index, boolean z)
    Sets the indexed element of the specified array object to the specified boolean value.
  • setByte(Object array, int index, byte b)
    Sets the indexed element of the specified array object to the specified byte value.
  • setChar(Object array, int index, char c)
    Sets the indexed element of the specified array object to the specified char value.
  • setShort(Object array, int index, short s)
    Sets the indexed component of the specified array object to the specified short value.
  • setInt(Object array, int index, int i)
    Sets the indexed component of the specified array object to the specified int value.
  • setLong(Object array, int index, long l)
    Sets the indexed component of the specified array object to the specified long value.
  • setFloat(Object array, int index, float f)
    Sets the indexed component of the specified array object to the specified float value.
  • setDouble(Object array, int index, double d)
    Sets the indexed component of the specified array object to the specified double value.

3.6 Common methods of java.lang.reflect.Modifier

Using Java Reflection API, the Modifier class cannot be instantiated and export static methods or constants that are used to decode the Java language modifiers for classes or members, which are encoded in an integer.

  • boolean isPublic(int mod)
    Returns true if the specified integer includes the public modifier.
  • boolean isPrivate(int mod)
    Returns true if the specified integer includes the private modifier.
  • boolean isProtected(int mod)
    Returns true if the specified integer includes the protected modifier.
  • boolean isStrict(int mod)
    Return true if the integer argument includes the strictfp modifier.
  • boolean isStatic(int mod)
    Returns true if the specified integer includes the static modifier.
  • boolean isFinal(int mod)
    Returns true if the specified integer includes the final modifier.
  • boolean isSynchronized(int mod)
    Returns true if the specified integer includes the synchronized modifier.
  • boolean isVolatile(int mod)
    Returns true if the specified integer includes the volatile modifier.
  • boolean isTransient(int mod)
    Returns true if the specified integer includes the transient modifier.
  • boolean isNative(int mod)
    Returns true if the specified integer includes the native modifier.
  • boolean isInterface(int mod)
    Returns true if the specified integer includes the interface modifier.
  • boolean isAbstract(int mod)
    Returns true if the specified integer includes the abstract modifier.
  • String toString(int mod)
    Returns a string containing a space-separated list of the names of the modifiers included in the specified integer.

4. Java Reflection Example

Create a java class named RentCar.java with the following code:

RentCar.java

01
02
03
04
05
06
07
08
09
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
package com.javacodegeeks.core.reflection;
 
public class RentCar {
 
    private int rate;
    private String type;
    public int price;
 
    public RentCar(int length) {
        if (length < 455) {
            type = "small";
            rate = 35;
        } else if ((length >= 455) && (length < 495)) {
            type = "mid-sized";
            rate = 45;
        } else if (length >= 495) {
            type = "large";
            rate = 55;
        }
    }
 
 
    public int getRate() {
        return rate;
    }
 
    public String getType() {
        return type;
    }
 
    public void setRate(int rate) {
        this.rate = rate;
    }
 
    public void setType(String type) {
        this.type = type;
    }
 
    public void computeRentalCost(int numDays) {
        price = numDays * rate;
        System.out
                .println("The cost of your rental car is " + price + " euros");
    }
}

This class will be called later at runtime.

Now, create another Java class named ReflectionExample.java with the following code:

ReflectionExample.java

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package com.javacodegeeks.core.reflection;
 
import java.lang.reflect.*;
import java.util.Arrays;
 
public class ReflectionExample {
    public static void main(String[] args) {
 
        // Obtain the class object if we know the name of the class
        Class rental = RentCar.class;
        try {
            // get the absolute name of the class
            String rentalClassPackage = rental.getName();
            System.out.println("Class Name is: " + rentalClassPackage);
 
            // get the simple name of the class (without package info)
            String rentalClassNoPackage = rental.getSimpleName();
            System.out.println("Class Name without package is: "
                    + rentalClassNoPackage);
 
            // get the package name of the class
            Package rentalPackage = rental.getPackage();
            System.out.println("Package Name is: " + rentalPackage);
 
            // get all the constructors of the class
            Constructor[] constructors = rental.getConstructors();
            System.out.println("Constructors are: "
                    + Arrays.toString(constructors));
 
            // get constructor with specific argument
            Constructor constructor = rental.getConstructor(Integer.TYPE);
 
            // initializing an object of the RentCar class
            RentCar rent = (RentCar) constructor.newInstance(455);
 
            // get all methods of the class including declared methods of
            // superclasses
            // in that case, superclass of RentCar is the class java.lang.Object
            Method[] allmethods = rental.getMethods();
            System.out.println("Methods are: " + Arrays.toString(allmethods));
            for (Method method : allmethods) {
                System.out.println("method = " + method.getName());
            }
 
            // get all methods declared in the class
            // but excludes inherited methods.
            Method[] declaredMethods = rental.getDeclaredMethods();
            System.out.println("Declared Methods are: "
                    + Arrays.toString(declaredMethods));
            for (Method dmethod : declaredMethods) {
                System.out.println("method = " + dmethod.getName());
            }
 
            // get method with specific name and parameters
            Method oneMethod = rental.getMethod("computeRentalCost",
                    new Class[] { Integer.TYPE });
            System.out.println("Method is: " + oneMethod);
 
            // call computeRentalCost method with parameter int
            oneMethod.invoke(rent, 4);
 
            // get all the parameters of computeRentalCost
            Class[] parameterTypes = oneMethod.getParameterTypes();
            System.out.println("Parameter types of computeRentalCost() are: "
                    + Arrays.toString(parameterTypes));
 
            // get the return type of computeRentalCost
            Class returnType = oneMethod.getReturnType();
            System.out.println("Return type is: " + returnType);
 
            // gets all the public member fields of the class RentCar
            Field[] fields = rental.getFields();
 
            System.out.println("Public Fields are: ");
            for (Field oneField : fields) {
                // get public field name
                Field field = rental.getField(oneField.getName());
                String fieldname = field.getName();
                System.out.println("Fieldname is: " + fieldname);
 
                // get public field type
                Object fieldType = field.getType();
                System.out.println("Type of field " + fieldname + " is: "
                        + fieldType);
 
                // get public field value
                Object value = field.get(rent);
                System.out.println("Value of field " + fieldname + " is: "
                        + value);
 
            }
 
            // How to access private member fields of the class
 
            // getDeclaredField() returns the private field
            Field privateField = RentCar.class.getDeclaredField("type");
 
            String name = privateField.getName();
            System.out.println("One private Fieldname is: " + name);
            // makes this private field instance accessible
            // for reflection use only, not normal code
            privateField.setAccessible(true);
 
            // get the value of this private field
            String fieldValue = (String) privateField.get(rent);
            System.out.println("fieldValue = " + fieldValue);
 
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

Let’s give a short explanation of the above code. Firstly, we obtain the class object of the class RentCar. Then, we use some methods from the class java.lang.Class so as to obtain the perspective information from the class RentCar. Afterwards, we retrieve the constructors of the class RentCar and we instantiate an object with the integer 455 as parameter. Also, we call two different methods for obtaining the methods provided by the class RentCar. The difference between the methods getMethods() and getDeclaredMethods() is that the first one retrieves all the methods provided by class RentCar including those methods inherited by the superclasses (in our case, this superclass is java.lang.Object), while the second one retrieves only the methods provided by our class.
Then, using the methods from the class java.lang.reflect.Method , we inspect informations of the computeRentalCost() method.
Afterwards, using the methods from the class java.lang.reflect.Field , we retrieve information of the public member fields of the class RentCar. In our case, only field int price is public.
Finally, we show a way to obtain information for private fields and for that purpose, we use the String type field which is private.

If we run the above code, we will have the following results:

Output

Class Name is: com.javacodegeeks.core.reflection.RentCar
Class Name without package is: RentCar
Package Name is: package com.javacodegeeks.core.reflection
Constructors are: [public com.javacodegeeks.core.reflection.RentCar(int)]
Methods are: [public void com.javacodegeeks.core.reflection.RentCar.setType(java.lang.String), public void com.javacodegeeks.core.reflection.RentCar.computeRentalCost(int), public int com.javacodegeeks.core.reflection.RentCar.getRate(), public void com.javacodegeeks.core.reflection.RentCar.setRate(int), public java.lang.String com.javacodegeeks.core.reflection.RentCar.getType(), 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()]
method = setType
method = computeRentalCost
method = getRate
method = setRate
method = getType
method = wait
method = wait
method = wait
method = equals
method = toString
method = hashCode
method = getClass
method = notify
method = notifyAll
Declared Methods are: [public void com.javacodegeeks.core.reflection.RentCar.setType(java.lang.String), public void com.javacodegeeks.core.reflection.RentCar.computeRentalCost(int), public int com.javacodegeeks.core.reflection.RentCar.getRate(), public void com.javacodegeeks.core.reflection.RentCar.setRate(int), public java.lang.String com.javacodegeeks.core.reflection.RentCar.getType()]
method = setType
method = computeRentalCost
method = getRate
method = setRate
method = getType
Method is: public void com.javacodegeeks.core.reflection.RentCar.computeRentalCost(int)
The cost of your rental car is 180 euros
Parameter types of computeRentalCost() are: [int]
Return type is: void
Public Fields are: 
Fieldname is: price
Type of field price is: int
Value of field price is: 180
One private Fieldname is: type
fieldValue = mid-sized

5. When to use reflection and when you should avoid it

Java Reflection is the process of modifying and analyzing all the capabilities of a class at runtime. Reflection API in Java is used to manipulate class and its members which include fields, methods and constructor at runtime. For example Java Reflection can be used to map properties in JSON files to getter/setter methods in Java objects. Furthermore, Reflection can be used to map the column names of a JDBC ResultSet to getter/setter methods in a Java object.

Nevertheless, we need to be careful using Java Reflection API and sometimes should avoid it. Some reasons are that you can lose the compile-time type safety (you’ll get an error at runtime which might affect end users if you don’t test well enough) or it can cause bugs when refactoring.

6. Pros and Cons

The advantages of the Java Reflections are:

  • Debugging: The reflection is used by debuggers to examine private members in classes.
  • Extensibility Features: An application may make use of user-defined classes to create instances of extensibility objects using their fully-qualified names.

The disadvantages of the Java Reflections are:

  • Exposure of Internals: The reflective code can break abstractions and change the behaviour with upgrades of the platform.
  • Performance Overhead:  reflective operations have slower performance and for that reason should be avoided in sections of code which are called frequently in performance-sensitive applications.

7. Download the source code

This was a Java Reflection example.

Download
Download the source code here: Java Reflection Example

Last updated on Mar. 23rd, 2020

Konstantina Dimtsa

Konstantina has graduated from the Department of Informatics and Telecommunications in National and Kapodistrian University of Athens (NKUA) and she is currently pursuing M.Sc studies in Advanced Information Systems at the same department. She is also working as a research associate for NKUA in the field of telecommunications. Her main interests lie in software engineering, web applications, databases and telecommunications.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
ASD
5 years ago

nice content……

Back to top button