Saturday, August 20, 2011

Java Reflection Notes

Here are some of the notes that I always had in my local txt file about Java Reflection.

What it is?

Ability to examine or modify the runtime behavior of applications running in the Java virtual machine

import java.lang.reflect

Object Reflection is a feature in Java which provides a way to get reflective information about classes and objects, such as:

  1. Getting information about methods and fields present inside the class at run time
  2. Creating a new instance of a class
  3. Getting and setting the object fields/methods directly by getting field reference
  4. Accessing/Invoking fields/methods even if they were private or protected... regardless of what the access modifier

Useful in monitoring application at runtime, also used for debugging or analysis.

---------------------------------------------------------------------------------

Drawbacks of Reflection

Performance

Reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

---------------------------------------------------------------------------------

Get the Class

1) myObject.getClass()

If an instance of an object is available

Class c = myObject.getClass();

byte[] bytes = new byte[1024];
Class c = bytes.getClass()

3) Class.forName()

If the fully-qualified name of a class is available

Class c = Class.forName("com.duke.MyLocaleServiceProvider");
Class cDoubleArray = Class.forName("[D"); //
same as double[].class
Class cStringArray = Class.forName("[[Ljava.lang.String;");

3) .class

if the type is available but there is no instance

// or if there is a primitive

boolean b;
Class c = b.getClass(); // compile-time error

Class c = boolean.class; // correct

Class c = int[][][].class;
Class c = java.io.PrintStream.class;

4) TYPE Field for Primitive Wrappers

Class c = Double.TYPE;

---------------------------------------------------------------------------------

Class.getSuperclass()
Returns the super class for the given class.

Class.getClasses()
Returns all the public classes, interfaces, and enums that are members of the class including inherited members.

Class[] c = Character.class.getClasses();
Character contains two member classes Character.Subset and Character.UnicodeBlock.

Class.getDeclaredClasses()
Returns all of the classes interfaces, and enums that are explicitly declared in this class.

Package p = c.getPackage();

---------------------------------------------------------------------------------


Class Methods for Locating Fields
Class API
List of members?
Inherited members?
Private members?
no
no
yes
no
yes
no
yes
no
yes
yes
yes
no


Class Methods for Locating Methods
Class API
List of members?
Inherited members?
Private members?
no
no
yes
no
yes
no
yes
no
yes
yes
yes
no

Class Methods for Locating Constructors
Class API
List of members?
Inherited members?
Private members?
no
N/A1
yes
no
N/A1
no
yes
N/A1
yes
yes
N/A1
no
1 Constructors are not inherited.


---------------------------------------------------------------------------------

// public String[] myVariable= { "Alice", "White Rabbit" };

Field chars = c.getDeclaredField("myVariable");
String[] newChars = { "Queen", "King" };
Book book = new Book();
chars.set(book, newChars);

---------------------------------------------------------------------------------

When extracting Class or class type - return type is Class
When extracting classes - Class[]

---------------------------------------------------------------------------------

Class c = f.getType();
if (c.isArray(){...}

Method[] allMethods = c.getDeclaredMethods();

m.getName()
m.getReturnType()
m.getParameterTypes()
m.getExceptionTypes()

m.getModifiers()

Type[] gpType = m.getGenericParameterTypes();

Class c = Class.forName(args[0]);
Object t = c.newInstance();

---------------------------------------------------------------------------------

// invoking method

// making accessible (even if it was private)
m.setAccessible(true);
Object o = m.invoke(t, new Locale(args[1], args[2], args[3]));

---------------------------------------------------------------------------------
c.getDeclaredConstructors();

Type[] gpType = ctor.getGenericParameterTypes();

// new instance

public class ConsoleCharset {
public static void main(String... args) {
Constructor[] ctors = Console.class.getDeclaredConstructors();
Constructor ctor = null;
for (int i = 0; i < ctors.length; i++) {
ctor = ctors[i];
if (ctor.getGenericParameterTypes().length == 0)
break;
}

try {
ctor.setAccessible(true);
Console c = (Console)ctor.newInstance();
Field f = c.getClass().getDeclaredField("cs");
f.setAccessible(true);
}
}
}

Note: Class.newInstance() will only succeed if the constructor is has zero arguments and is already accessible. Otherwise, it is necessary to use Constructor.newInstance() as in the above example.

---------------------------------------------------------------------------------

1) Suppse you have ClassA and ClassB
One way to create an instance of ClassB in ClassA is
Class A
{
ClassB b = new ClassB();
}
What are the other ways to do it?

Java reflection will work in this case:
--
B b =(B) Class.forName("B").newInstance();

---------------------------------------------------------------------------------

// cast

f.setAccessible(true);
char[] cbVal = char[].class.cast(f.get(br));


// get and set array

Field f = c.getDeclaredField("cb");
char[] newVal = {};
f.set(br, newVal);

---------------------------------------------------------------------------------

References -

http://download.oracle.com/javase/tutorial/reflect/index.html


1 comment: