Reflection – 1

Reflection in Java is a powerful feature that allows a program to examine or introspect its own structure at runtime.

It enables the program to inspect and manipulate classes, interfaces, fields, methods, and constructors dynamically, without knowing their names at compile time.

Using reflection, we can do the following at runtime :

  • Obtain class information : get information about a class, such as its name, superclass, implemented interfaces, and modifiers;
  • Create instances : create objects of classes dynamically, even if the class name is not known until runtime;
  • Access fields : access and modify the fields (variables) of a class, regardless of their access level (public, private, protected, or default);
  • Invoke methods: invoke methods on objects, even if the method names are not known at compile time.

Reflection is primarily used in frameworks, libraries, and tools that need to work with unknown classes or provide extensibility points.

However, it’s important to note that while reflection can be a powerful tool, it should be used judiciously, as it may lead to reduced performance and can make the code less readable and maintainable.

What You Need

  • About 14 minutes
  • A favorite text editor or IDE
  • Java 8 or later

1. The Class class

The Class class is a special class that represents the metadata of a class at runtime.

It is a fundamental part of the Java Reflection API.

Because it acts as a gateway to access and interact with the runtime properties of a Java class, such as its fields, methods, constructors, superclasses, implemented interfaces, and more.

Instances of the Class class are objects representing other language classes.

These instances are automatically created by the virtual machine when loading the classes.

For each class, there is only one instance representing itself.

For instance, Person Class has only one Person Class Instance but can have more than one Person Instances.

1.1 Get an object of type Class

The Class class does not have a public constructor but there are several ways to obtain an object of the Class class.

  • From the class name : classname.class;
  • From the object : object.getClass();
  • From the fully qualified class name : Class.forName(fully qualified class name).
public class ClassTest1 {
    public static void main(String[] args) throws ClassNotFoundException {
        // From class
        Class<?> clazz = String.class;

        System.out.println(clazz);

        // From object
        clazz = "tom".getClass();

        System.out.println(clazz);

        // From fully qualified class name
        clazz = Class.forName("java.lang.String");

        System.out.println(clazz);
    }
}

The output of above code snippet is below :

class java.lang.String
class java.lang.String
class java.lang.String

1.2 The methods of the Class class

The Class class provides many methods for obtaining information about the class it represents.

Here are some of the methods :

MethodRole
static Class forName(String)Returns the Class object associated with the class or interface with the given string name.
Class[] getClasses()Returns an array containing Class objects representing all the public classes and interfaces that are members of the class represented by this Class object.
Constructor[] getConstructors()Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object.
Class[] getDeclaredClasses()Returns an array of Class objects reflecting all the classes and interfaces declared as members of the class represented by this Class object.
Constructor[] getDeclaredConstructors()Returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object.
Field[] getDeclaredFields()Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object.
Method[] getDeclaredMethods()Returns an array containing Method objects reflecting all the declared methods of the class or interface represented by this Class object, including public, protected, default (package) access, and private methods, but excluding inherited methods.
Field[] getFields()Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object.
Class[] getInterfaces()Determines the interfaces implemented by the class or interface represented by this object.
Method[] getMethods()Returns an array containing Method objects reflecting all the public 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.
int getModifiers()Returns the Java language modifiers for this class or interface, encoded in an integer.
Package getPackage()Gets the package for this class.
Classe getSuperClass()Returns the Class representing the super class of the entity (class, interface, primitive type or void) represented by this Class.
boolean isArray()Determines if this Class object represents an array class.
boolean IsInterface()Determines if the specified Class object represents an interface type.
Object newInstance()Creates a new instance of the class represented by this Class object.

2. Finding class information

By using the methods of the Class class, it is possible to obtain almost any information about a class.

2.1 Finding the parent class of a class

The Class class has a getSuperClass() method which returns an object of the Class class representing the parent class if it exists otherwise it returns null.

To obtain the entire hierarchy of a class, all we have to do is successively call this method on the object it has returned.

import java.util.ArrayList;
import java.util.List;

public class ClassTest3 {
    public static void main(String[] args) {
        List<String> hierarchy = new ArrayList<>();

        Class<?> child = Apple.class;

        hierarchy.add(child.getName());

        Class<?> parent = child.getSuperclass();

        while (parent != null) {
            hierarchy.add(parent.getName());

            child = parent;
            parent = parent.getSuperclass();
        }

        hierarchy.forEach(System.out::println);
    }

    private static class Food {

    }

    private static class Fruit extends Food {

    }

    private static class Apple extends Fruit {

    }
}

The output of above code snippet is below :

ClassTest3$Apple
ClassTest3$Fruit
ClassTest3$Food
java.lang.Object

2.2 Finding modifiers of a class

The Class class has a getModifiers() method that returns an integer representing the class modifiers.

To decode this value, the Modifier class has several methods which expect this integer as a parameter and which return a boolean according to their function.

MethodRole
boolean isAbstract(int)Return true if the integer argument includes the abstract modifier, false otherwise.
boolean isFinal(int)Return true if the integer argument includes the final modifier, false otherwise.
boolean isInterface(int)Return true if the integer argument includes the interface modifier, false otherwise.
boolean isNative(int)Return true if the integer argument includes the native modifier, false otherwise.
boolean isPrivate(int)Return true if the integer argument includes the private modifier, false otherwise.
boolean isProtected(int)Return true if the integer argument includes the protected modifier, false otherwise.
boolean isPublic(int)Return true if the integer argument includes the public modifier, false otherwise.
boolean isStatic(int)Return true if the integer argument includes the static modifier, false otherwise.
boolean isSynchronized(int)Return true if the integer argument includes the synchronized modifier, false otherwise.
boolean isTransient(int)Return true if the integer argument includes the transient modifier, false otherwise.
boolean isVolatile(int)Return true if the integer argument includes the volatile modifier, false otherwise.
import java.lang.reflect.Modifier;

public class ClassTest4 {
    public static void main(String[] args) {
        int mod = Person.class.getModifiers();

        System.out.println("isPrivate = " + Modifier.isPrivate(mod));
        System.out.println("isStatic = " + Modifier.isStatic(mod));
        System.out.println("isFinal = " + Modifier.isFinal(mod));
    }

    private static final class Person {
    }
}

Below is the output of above code snippet :

isPrivate = true
isStatic = true
isFinal = true

2.3 Finding interfaces implemented by a class

The Class class has a getInterfaces() method which returns an array of Class type objects containing the interfaces implemented by the class.

public class ClassTest5 {
    public static void main(String[] args) {
        Duck duck = new Duck();

        duck.speak();
        duck.fly();
        duck.swim();

        System.out.println();

        Class<?>[] interfaces = duck.getClass().getInterfaces();

        for (Class<?> intf : interfaces) {
            System.out.println(intf.getName());
        }
    }

    private interface Animal {
        void speak();
    }

    private interface Swimmable {
        void swim();
    }

    private interface Flyable {
        void fly();
    }

    private static class Duck implements Animal, Swimmable, Flyable {
        @Override
        public void speak() {
            System.out.println("Quack");
        }

        @Override
        public void fly() {
            System.out.println(this.getClass().getSimpleName() + " flying");
        }

        @Override
        public void swim() {
            System.out.println(this.getClass().getSimpleName() + " swimming");
        }
    }
}

The output of above code snippet is below :

Quack
Duck flying
Duck swimming

ClassTest5$Animal
ClassTest5$Swimmable
ClassTest5$Flyable

2.4 Searching public fields

The Class class has a getFields() method which returns the public attributes of the class.

This method returns an array of Field type objects.

The Class class also has a getField() method which expects an attribute name as a parameter and returns an object of type Field if this is defined in the class or in one of its parent classes.

If the class does not contain an attribute whose name matches the provided parameter, the getField() method throws an exception of the NoSuchFieldException class.

The Field class represents an attribute of a class or an interface and allows to obtain information about this attribute.

It has several methods :

MethodRole
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.
Class getDeclaringClass()Returns the Class object representing the class or interface that declares the field represented by this Field object.
int getModifiers()Returns the Java language modifiers for the field represented by this Field object, as an integer.
Object get(Object)Returns the value of the field represented by this Field, on the specified object.
import java.lang.reflect.Field;

public class ClassTest6 {
    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        Person p = new Person();
        p.name = "tom";
        p.age = 18;

        System.out.println(p);
        System.out.println();

        Class<?> clazz = p.getClass();
        for (Field field : clazz.getFields()) {
            System.out.println("Name = " + field.getName());
            System.out.println("Type = " + field.getType());
            Object value = field.get(p);
            System.out.println("Value = " + value);
            System.out.println();
        }
    }

    private static class Person {
        public String name;
        public int age;

        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    }
}

Below is the output of above code snippet :

Person [name=tom, age=18]

Name = name
Type = class java.lang.String
Value = tom

Name = age
Type = int
Value = 18

2.5 Finding class constructors

The Class class has a getConstructors() method which returns an array of Constructor type objects containing the constructors of the class.

The Constructor class represents a constructor of a class and has several methods :

MethodRole
String getName()Returns the name of this constructor, as a string.
Class[] getExceptionTypes()Returns an array of Class objects that represent the types of exceptions declared to be thrown by the underlying executable represented by this object.
Class[] getParametersType()Returns an array of Class objects that represent the formal parameter types, in declaration order, of the executable represented by this object.
int getModifiers()Returns the Java language modifiers for the executable represented by this object.
Object newInstance(Object[])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.
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ClassTest7 {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        Class<?> clazz = Person.class;
        Constructor<?> constructor = clazz.getConstructor(String.class, int.class);

        System.out.println("constructor's name = " + constructor.getName());

        Class<?>[] parameters = constructor.getParameterTypes();

        for (int i = 0; i < parameters.length; i++) {
            Class<?> parameter = parameters[i];
            System.out.println("constructor's parameter " + (i + 1) + " = " + parameter.getName());
        }

        Person p = (Person) constructor.newInstance("tom", 18);
        System.out.println(p);
    }

    private static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    }
}

The output of above code snippet is below :

constructor's name = ClassTest7$Person
constructor's parameter 1 = java.lang.String
constructor's parameter 2 = int
Person [name=tom, age=18]

2.6 The search for public methods

The Class class has getMethods(), which returns the public methods which are declared in the class or which are inherited from parent classes.

It returns an array of instances of the Method class from the java.lang.reflect package.

A method is characterized by a name, a return value, a list of parameters, a list of exceptions and a class to which it belongs.

The Method class contains several methods :

MethodRole
Class[] getParameterTypesReturns an array of Class objects that represent the formal parameter types, in declaration order, of the executable represented by this object.
Class getReturnTypeReturns a Class object that represents the formal return type of the method represented by this Method object.
String getName()Returns the name of the method represented by this Method object, as a String.
int getModifiers()Returns the Java language modifiers for the executable represented by this object.
Class[] getExceptionTypesReturns an array of Class objects that represent the types of exceptions declared to be thrown by the underlying executable represented by this object.
Class getDeclaringClass[]Returns the Class object representing the class or interface that declares the executable represented by this object.
import java.lang.reflect.Method;

public class ClassTest8 {
    public static void main(String[] args) {
        Person p = new Person("tom", 18);
        System.out.println(p);
        System.out.println();

        Class<?> clazz = p.getClass();
        Method[] methods = clazz.getMethods();

        for (Method method : methods) {
            System.out.println("method's name = " + method.getName());
            Class<?>[] parameters = method.getParameterTypes();
            for (int i = 0; i < parameters.length; i++) {
                System.out.println("method's parameter = " + parameters[i].getName());
            }
            System.out.println("method's return type = " + method.getReturnType());
            System.out.println();
        }
    }

    private static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    }
}

The output of above code snippet is below :

Person [name=tom, age=18]

method's name = toString
method's return type = class java.lang.String

method's name = equals
method's parameter = java.lang.Object
method's return type = boolean

method's name = hashCode
method's return type = int

method's name = getClass
method's return type = class java.lang.Class

method's name = notify
method's return type = void

method's name = notifyAll
method's return type = void

method's name = wait
method's parameter = long
method's return type = void

method's name = wait
method's parameter = long
method's parameter = int
method's return type = void

method's name = wait
method's return type = void

2.7 The search for non-public methods

The method getDeclaredMethods() returns an array containing Method objects reflecting all the declared methods of the class or interface represented by this Class object, including public, protected, default (package) access, and private methods, but excluding inherited methods.

import java.lang.reflect.Method;

public class ClassTest9 {
    public static void main(String[] args) {
        Person p = new Person("tom", 18);

        System.out.println(p);
        System.out.println();

        Class<?> clazz = p.getClass();

        Method[] methods = clazz.getMethods();

        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            System.out.println("method " + i + " = " + method.getName());
        }

        System.out.println();

        Method[] declaredMethods = clazz.getDeclaredMethods();

        for (int i = 0; i < declaredMethods.length; i++) {
            Method method = declaredMethods[i];

            System.out.println("declared method " + i + " = " + method.getName());
        }
    }

    private static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        protected void greet() {
            speak("hi, i am " + this.name);
        }

        private void speak(String words) {
            System.out.println(words);
        }

        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    }
}

Below is the output of above code snippet :

Person [name=tom, age=18]

method 0 = toString
method 1 = equals
method 2 = hashCode
method 3 = getClass
method 4 = notify
method 5 = notifyAll
method 6 = wait
method 7 = wait
method 8 = wait

declared method 0 = toString
declared method 1 = greet
declared method 2 = speak