Reflection is a language’s ability to inspect and dynamically call classes, methods, attributes, etc. at runtime.
Even if you do not know the type of the object at compile time, it is possible to call it’s methods, get it’s properties … at runtime.
In Java Objects have the getClass()
method that allows you to find the object’s class at runtime.
Useful?
Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing the names of the classes, methods etc. at compile time. You can instantiate new objects, invoke methods and get/set field values using reflection.
It’s pretty common in libraries/APIs and in programs that analyse your code.
Danger
It depends on the language but in Java for example it might be a signal of bad design.
Code
On StackOverflow I found the dump
method that is used to find object properties at runtime while the type is unknown at compile time.
I wrote some quick code around it to get a working example.
import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import java.lang.reflect.Array; import java.lang.reflect.Field; public class Main { public static void main(String[] args) { Company c = Company.builder() .name("Waggie") .sector("IT") .build(); Employee e = Employee.builder() .age(25) .designation("Hof") .name("Nick") .salary(40000.4D) .company(c) .build(); String objectRepresentation = dump(e, 0); System.out.println(objectRepresentation); } public static String dump(Object o, int callCount) { callCount++; StringBuffer tabs = new StringBuffer(); for (int k = 0; k < callCount; k++) { tabs.append("\t"); } StringBuffer buffer = new StringBuffer(); Class oClass = o.getClass(); if (oClass.isArray()) { buffer.append("\n"); buffer.append(tabs.toString()); buffer.append("["); for (int i = 0; i < Array.getLength(o); i++) { if (i < 0) buffer.append(","); Object value = Array.get(o, i); if (value.getClass().isPrimitive() || value.getClass() == java.lang.Long.class || value.getClass() == java.lang.String.class || value.getClass() == java.lang.Integer.class || value.getClass() == java.lang.Boolean.class ) { buffer.append(value); } else { buffer.append(dump(value, callCount)); } } buffer.append(tabs.toString()); buffer.append("]\n"); } else { buffer.append("\n"); buffer.append(tabs.toString()); buffer.append("{\n"); while (oClass != null) { Field[] fields = oClass.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { buffer.append(tabs.toString()); fields[i].setAccessible(true); buffer.append(fields[i].getName()); buffer.append("="); try { Object value = fields[i].get(o); if (value != null) { if (value.getClass().isPrimitive() || value.getClass() == java.lang.Long.class || value.getClass() == java.lang.Double.class || value.getClass() == java.lang.String.class || value.getClass() == java.lang.Integer.class || value.getClass() == java.lang.Boolean.class ) { buffer.append(value); } else { buffer.append(dump(value, callCount)); } } } catch (IllegalAccessException e) { buffer.append(e.getMessage()); } buffer.append("\n"); } oClass = oClass.getSuperclass(); } buffer.append(tabs.toString()); buffer.append("}\n"); } return buffer.toString(); } } @Data @AllArgsConstructor @Builder class Employee { String name; int age; String designation; double salary; Company company; } @Data @Builder class Company{ String name; String sector; }
This will output the object’s properties:
{ name=Nick age=25 designation=Hof salary=40000.4 company= { name=Waggie sector=IT } }