Here is an exercise for you!
Write a java program that take two or more command line arguments. 1st argument is a class name. 2nd argument is a method name. Rest of the arguments are string values to be passed in to that method.
Your program has to load the class specified in first argument (this class may not be available at compile time). Create an instance of that class. Then invoke the method given in the 2nd argument on that object passing the values given in rest of the arguments as parameters to that function. To simplify things lets say all parameters are string.
The answer is reflections. To give you a very simplified description, Reflections allow you to access members of a class/object dynamically in run time without having to hard-code things in the source code. This is slower than hard-coding. But it is very useful when the class/methods/fields that you need to access are not known or not available at compile time. Also in some cases you can do cool things like accessing private members.
Lets see how to do the above task step by step.
1. Load the class specified in first parameter.
This part is not really reflection, but this is where most reflection code start. Before you can access members of a class you need the class itself. How do we load a class of which the name is inside a string. Well! if you have done some JDBC coding you have done this already. Yes you can use Class.forName(….) method. But this time we need a reference to the class itself. For that we use Class class.
Class myClass = Class.forName(args);
If the value in args array element is a valid class name above line should place a reference to the Class object of that class in myClass variable. Otherwise you will be greeted with a ClassNotFoundException.
2. Create an instance of that class.
For simplicity lets assume that we use default constructor. In that case, creating an instance of a class is as simple as
Object myInstance = myClass.newInstance();
If you need to use a non-default constructor that is bit tricky. First you need to call getConstructor(Class… parameterTypes) method on your Class object to get a Constructor object and then call newInstance(Object… initargs) method on the Constructor object to create the object. Don’t worry about these wired looking parameters of these methods for the moment. Because we are not going to use those methods for this example and also after next step you will know all about those parameters.
3. Get the Method
Well this is the tricky part. Before you can invoke a method you must first get a Method object that represent the method. Question is how do you do that. Well if you have learned the java basics, you should know that in java, a method is identified by its signature. And the signature has two parts, method name and parameters types.
We have the method name in 2nd argument passed in to our program. We assume that the number of parameters in the method is equal to the additional parameters passed in to our program (total parameters – 2). And we have the class object.
Since we have the Class object all we got to do is call getMethod(String name, Class… parameterTypes) method on it, passing method name and an array of class objects to represent the list of parameter types.
Lets first make the Class array to represent parameter types…
Class parameterTypes = new Class[args.length-2];
We assume that all parameters are of type String. So we can fill the array with String class objects.
for (int i=0; i<parameterTypes.length; i++) parameterTypes[i] = String.class;
Now we have everything we need to define the method signature, therefore we are ready to call getMethod function
Method myMethod = myClass.getMethod(args, parameterTypes)
If you revisit step 2 where I touched on getConstructur function, the class array parameter on that function is also used to identify the signature of constructor. And it is as same as 2nd parameter on getMethod function.
4. Invoke the method
Now we just have the method. All that is left is to invoke it.
Once we have the Method instance you just have to call invoke(Object obj, Object… args) method on Method object. First parameter of this method is the object on which we invoke the method. That object should belong to the class that contain the method that we are trying to invoke. Second parameter is an array of objects containing the parameters to be passed in to the method that we invoke. Constructing that array is similar to creating the parameter types array in previous step. In this step we also assume that invoking this method will not cause any Exception. Also we ignore any return value from the method. You can figure out how to deal with those things by reading the documentation.
Ok, lets get down to work. We already have the object that we need to pass in to first parameter. We created that in step 2. All we need to do is to construct the array of parameters. This time since we already have the parameters as a part of incoming argument array to the program, we can use System.arraycopy method.
String parameters = new String[args.length-2]; System.arraycopy(args, 2, parameters, 0, parameters.length);
Now we got everything we need to invoke the thing.
Lets just put all above together…
Well, it looks like an awful lot of code just to invoke a single method. But as you can see above, the method we need to invoke or its class is not there in the code. Reflections can look messy but in complex applications it is a very powerful tool and most often it is also the cleanest way to do it.
This is a very basic example of using java reflections. It is not possible to cover everything about reflections in one post. If you read java documentation on package java.lang.reflect you will be able to learn lot more. I’ll write few more posts on this topic in the future.
Tags: java, Java Programming, java.lang.Class, java.lang.reflect, java.lang.reflect.Constructor, java.lang.reflect.Method, Programming, reflect, Reflection
6 comments on “Java Core API: Introduction to Java Reflections”
You must log in to post a comment.
Your article was very useful for me. Though I have used forName() and newInstance() methods to load JDBC Driver class in Java programs I had no clear idea about those methods.
Having read your blog post I got a good understanding of those methods.
Is there a way in C++ to implement such case.?
Thanks for the comment. To my knowledge C++ do not provide anything like reflections on its own. However each compiler has a way of keeping track of addresses of each class member (functions/attributes) in a table.
All you need is a way to get a function pointer when you know the function name. I think there is a function to do that when it comes to dealing with DLL files. But I don’t remember the name of that right now.
In one of the application I have worked on we have a way of each class registering itself in a repository, which is like a runtime database. We then use this database to dynamically create objects and call methods. That is one way of doing it.
Also Reflections in C++ is an area where lot of research is done. If you google for ‘reflection for C++’ you will find lots of information including few very promising open source APIs.
There is a LGPL C++ library called Reflex which provide reflection by parsing header files. But I have never used it.
BTW, In .Net there is a Reflections library. If you write managed C++ or any .Net language you can use that.
Reason why you use Class.forName and newInstance method in JDBC is because every JDBC Driver must be registered in JDBC DriverManager before you can call getConnection method to create a connection.
Most driver classes either has a static code block to register itself or it put the code of registering itself inside its default constructor. So if it is in the static code block it will get executed and registered when you call Class.forName. If it is in the default constructor it will get invoked when you call newInstance. Thats why you need to do that when we use JDBC.
nice 🙂 ure blog has different types of articles. Thats a great work 🙂 keep it up….
[…] a comment » This is a follow-up to my earlier post on Java Reflections. In the earlier post I just showed how to invoke methods of an object dynamically using […]
[…] is a follow-up to my earlier post on Java Reflections. In the earlier post I just showed how to invoke methods of an object dynamically using […]