Reflection in java is an API that examines or modifies the behavior of classes, methods, fields and interfaces during runtime. It is called reflection because of its ability to examine other code, or itself, within the same system. This can be done even when a particular class is inaccessible.
package com.javabykiran.reflect;
/*
* @author Java By Kiran
*/
public class Employee {
public void m1() {
System.out.println("I am in m1");
}
public void m2() {
System.out.println("I am in m2");
}
public void m3() {
System.out.println("I am in m3");
}
public void m4() {
System.out.println("I am in m4");
}
}
Now we have been asked to call all methods of this class as per client requirement.
If you observe order of methods of every client, you’ll find that they’are all different. To fulfill the above given requirement, we will follow the steps given below :
package com.javabykiran.reflect;
/*
* @author Java By Kiran
*/
public class EmployeeTest {
public static void main(String[] args) {
// Client 1 - requirement
System.out.println("Client 1 Requirement");
Employee employee=new Employee();
employee.m1();
employee.m2();
employee.m4();
employee.m3();
// Client 2 - requirement
System.out.println("Client 2 Requirement");
Employee employee1=new Employee();
employee1.m4();
employee1.m2();
employee1.m4();
// Client 3 - requirement
System.out.println("Client 3 Requirement");
Employee employee2=new Employee();
employee2.m1();
employee2.m2();
employee2.m3();
employee2.m4();
// Like above for all clients...
}
}
Output:
Client 1 Requirement
I am in m1
I am in m2
I am in m4
I am in m3
Client 2 Requirement
I am in m4
I am in m2
I am in m4
Client 3 Requirement
I am in m1
I am in m2
I am in m3
I am in m4
Let’s say there are many clients and their requirements will be different. We will go on writing code as shown above EmployeeTest.java
This is not dynamic. Tomorrow, any addition of client causes our code to change. This is what we don't want to do. Hence, this coding practice is not good.
To solve this requirement we must use reflection. We will be able to solve the above given requirement at a later stage of this chapter once we understand reflection completely.
Next Requirement
We have an excel sheet below:
Roll No | Student | Student Phone No | Remark |
---|---|---|---|
1733 | Kiran | 8888809416 | Java by kiran |
1738 | Jayshree | 9552343698 | www.javabykiran.com |
Now we want to insert data from the excel sheet to table Student as shown below:
To use core java logic for insertion easily with less optimized code, you must use reflection.
Important points to remember about Reflection:
Java Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing the names of the classes, methods, etc.
We can create objects dynamically by using reflection
We can create an object of a class having private constructors as well, from outside a class. Hence, we can instantiate class from outside. This is not possible by simply creating an object by using new operator.
This chapter will explain the basics of Java Reflection including how to work with arrays, annotations, generics and dynamic proxies, and how to do dynamic class loading and reloading. It will also show you how to do more specific tasks, like reading all getter methods of a class, or accessing private fields and methods of a class.
This chapter will also clear up some of the confusion out there about what Generics information is available at runtime. Some people claim that all Generics information is lost at runtime. This is not true.
Package in which all reflection classes are existing :
java.lang.reflect
For reflection we must know class [Class] first.
Class is class name in java and exists in java.lang package.
Instances of the class Class represent classes and interfaces in a running Java application.
In reflection we will deal with preexisting classes like Method, Field, and Constructor and so on.
Let's say we have simple class as shown below:
package com.javabykiran.reflect;
public class B {
B() {
System.out.println ("B Zero parameter const");
}
B(int x) {
System.out.println ("B One parameter const");
}
int a=90;
void m1() {
System.out.println ("B -m1");
}
int m2() {
System.out.println ("B - m2");
return 10;
}
}
To use reflection we must first get object of Class class.
The example below shows two ways.
package com.javabykiran.reflect;
public class A {
public static void main(String[] args) {
//First scenario Class c = B.class;
//Second scenario
B b=new B();
Class cl = b.getClass();
}
}
In this example we will get all the information about class B by using c and c1 reference variables by using methods of Class class.
Above given is class B (every information means --> two constructors, two methods and one variable).
Here we can see the complete class B but sometimes you only know class name not members of that class. Then we must go for reflection.
To complete this we use the below methods of class Class [In the second step we have added some reflection code in existing class A].
i. To Fetch All methods use the class below:
package com.javabykiran.reflect;
import java.lang.reflect.Method;
public class A {
public static void main(String[] args) {
// First scenario
Class c = B.class;
// Second scenario
B b = new B();
Class c1 = b.getClass();
// GET ALL METHODS OF CLASS B
// return all public methods of B and inherited methods
Method[] methodList = c1.getMethods();
// for each loop you can use simple for loop as //well
for (Method method : methodList) {
System.out.println("method name >> " + method.getName());
}
// below code returns all public/private/protected/default methods of B only
Method[] methodListAll = c1.getDeclaredMethods();
// for each loop you can also use simple for loop
for(Method method : methodListAll) {
System.out.println("declared method name >> " + method.getName());
}
}
}
Output:
B Zero parameter const
method name >> wait
method name >> wait
method name >> wait
method name >> equals
method name >> toString
method name >> hashCode
method name >> getClass
method name >> notify
method name >> notifyAll
declared method name >> m1
declared method name >> m2
ii. To Fetch All Variables in class B
Add the lines below n class A
// GET ALL VARIABLES OF CLASS B
Field [] fields=c1.getDeclaredFields ();
for(Field field:fields){
System.out.println("field name >> "+field.getName());
}
iii. Getting and Setting Field Values
Once you have obtained a Field reference you can get and set its values using the Field.get() and Field.set()methods, like this: // to execute this add variables in class B
Class aClass = B.class;
Field field = aClass.getField("a"); //we are getting one variable
B bb = new B();
field.set(bb, 45)
package com.javabykiran.reflect;
import java.lang.reflect.Method;
public class PrivateObject {
private String privateString = null;
public PrivateObject(String privateString)
{
this.privateString = privateString;
}
private String getPrivateString() {
return this.privateString;
}
public static void main(String[] args) throws Exception {
PrivateObject privateObject = new PrivateObject("The Private Value");
Method privateMethod = PrivateObject.class.getDeclaredMethod("getPrivateString", null);
privateMethod.setAccessible(true);
String val=(String)privateMethod.invoke(privateObject, null);
System.out.println("returnValue = " + val);
}
}
This code example will print out the text "return Value = The Private Value", which is the value returned by the method getPrivateString () when invoked on the PrivateObject instance created at the beginning of the code sample.
Notice the use of the method PrivateObject.class.getDeclaredMethod ("privateString"). This method helps to call private method.
It only returns methods declared in that particular class, not methods declared in any superclasses.
Observe the line in bold too. By calling Method.setAcessible (true), you turn off the access checks for this particular Method instance for reflection calls only. Now you can access it even if it is private, protected or package scope, even if the caller is not a part of those scopes. You can't access the method using normal code. The compiler won't allow it.
Dynamic class loading is a very helpful feature in java that lets us load java code which we are unaware of before the starting of a program. It is invoked at runtime.
Use Class.forName in this case.
package com.javabykiran.reflect;
/*
* @author Java By Kiran
*/
public class DynaLoad {
Object anyClassObject(String clsName)throws Exception {
Object object = Class.forName(clsName).newInstance();
return object;
}
public static void main(String[]args)throws Exception {
DynaLoad dynaLoad=new DynaLoad();
/* This will give A class object we will pass class name as a String*/
A a=(A)dynaLoad.anyClassObject("com.jbk.A");
// now do operations with a
/*This will give A class object we will pass class name as a String*/
Employee employee=(Employee)dynaLoad.anyClassObject ("com.jbk.Employee");
// now do operations with employee
}
}
In this example we see that the single method we used to get a class object. If we do not use this way we need to hard code like:
A a =new A();
// can't be changed later // we must know class name
Employee employee =new Employee ();
// can't be changed later // we must know class name.
If somebody asks why we use class.forname, the answer will be dynamic class object creation.