Search code examples
javareflectionclassfieldclassloader

How to access class fields of a class that I only know it by its string name?


For instance, I have a class called "My_Class_X123.java" like this :

public class My_Class_X123    // This file was generated by a java program
{
  static String ABC[]={"1","2",...};
  int XYZ=0;
}

When I wrote my program I didn't know there would be a class by this name, but at run time I found out a class by the name of "My_Class_X123.java" exists and I want to use its fields such as ABC and XYZ above, how to get those values ?


OK, I got the answer, it's something like this :

  try
  {
    Class myClass=Class.forName("My_Class_X123");
    Field fields[]=myClass.getDeclaredFields();
    String New_ABC[]=String[].class.cast(fields[0].get(String[].class));
  }
  catch (Exception e) { e.printStackTrace(); }

Wouldn't it be nice to have some sample code like this in the java doc, to show user how to do it !

Frank


Solution

  • You need to use Reflection. A while back I wrote some JSTL tag utilities that does this sort of thing. One function checks to see if a class is an instance of a passed-in string (instanceof basically). The other checks to see whether a class has a specified property (hasProperty). The following code snippet should help:

    //Checks to see if Object 'o' is an instance of the class in the string "className"
    public static boolean instanceOf(Object o, String className) {
        boolean returnValue;
    
        try {
            returnValue = Class.forName(className).isInstance(o);
        }
    
        catch(ClassNotFoundException e) {
            returnValue = false;
        }
    
        return returnValue;
    }
    
    //Checks to see if Object 'o' has a property specified in "propertyName"
    public static boolean hasProperty(Object o, String propertyName) {
        boolean methodFound = false;
        int i = 0;
    
        Class myClass = o.getClass();
        String methodName = "get" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
        Method[] methods = myClass.getMethods();
    
        while(i < methods.length && !methodFound) {
            methodFound = methods[i].getName().compareTo(methodName) == 0;
            i++;
        }
    
        return methodFound;
    }
    

    Pay particular attention to the Class.forName method in the first method (which loads and initializes a class) and getMethods() method in the second function, which returns all methods defined for a class.

    What you probably want is Class.forName which also initializes the class. After that you can use newInstance to get a new instance of that class (if you need one). To access the fields, you need to use the Method objects that you got from getMethod(). Use the invoke method on those objects. If those methods are getter methods, then you now have access to the field you want.

    EDIT

    After looking at the code in your question, I realized that you need getters and setters for those attributes. So assuming you have getABC and getXYZ defined, here is a somewhat contrived example:

    public Object reflectionDemo(String className, String getter) throws ClassNotFoundException, NoSuchMethodException {
    
       Object fieldValue;
       Class myClass = Class.forName(className);
       Object myClassInstance = myClass.newInstance(); //to get an instance of the class       
    
       if(myClassInstance instanceof My_Class_X123) {       
          //null because we are not specifying the kind of arguments that class takes
          Method getterMethod = myClass.getMethod(getter, null); 
          //null because the method takes no arguments
          //Also in the scenario that the method is static one, it is not necessary to pass in an instance, so in that case, the first parameter can be null.
          fieldValue = getterMethod.invoke(myClassInstance, null);
       } 
    
       return fieldValue;
    }
    

    The above approach is more generic. If you only want the fields, then you can use the method James described:

    myClass = null;
    try {
      myClass = Class.forName(className);
      Field[] fields = myClass.getDeclaredFields();
    
      for(Field field : fields) {
        //do whatever with the field. Look at the API reference at http://java.sun.com/javase/6/docs/api/java/lang/reflect/Field.html    
      }
    }
    
    catch(Exception e) {
      //handle exception
    }