views:

135

answers:

3

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

A: 

Use java.lang.reflect. First use ClassLoader to get a Class for the class, then you can call newInstance to get an object, then you can use the reflection interfaces to get the fields.

A comprehensive tutorial live here.

bmargulies
Any sample code ?
Frank
+3  A: 

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
}
Vivin Paliath
But how do I get the "o" object first ?
Frank
I've added an example.
Vivin Paliath
At programming time I don't know the name of the class, so this line won't work : "if(myClassInstance instanceof My_Class_X123)"
Frank
Oops, my bad. All you can do in that case, really, is take out the `instanceof` and try and get the Method with the specified name anyway. This will throw a `NoSuchMethodException` if the method does not exist, so you need a `try...catch` block.
Vivin Paliath
A: 

If you just need the class fields you don't even need to create an instance, just as long as you use reflection to get the Class you can use getDeclaredFields() method to get the name of the fields and their values, e.g.

Class myClass = null;

try {
    myClass = Class.forName("package.ClassName");
    Field[] fields = myClass.getDeclaredFields();

    for (Field field : fields) {
         System.out.println("Field type is: " + field.getType());
         System.out.println("Field name is: " + field.getName());
    }
} catch (Exception e) {
}
James
Ooh, nice! Somehow that slipped by me :) I have a question though, why do you have the code that gets the declared field inside your catch block? Wouldn't `myClass` be `null`?
Vivin Paliath
Whoops, didn't see I had it in the wrong place!
James
I do need to use the values in the fields, not just their names.
Frank
Alright, so how do I get the values "1","2" ... from my sample code's ABC[] ?
Frank
Frank, look at the Java API documentation for the Field object.
Vivin Paliath
Yes I have, but still can't figure out how, it'll be nice if it has sample usages in the doc, what I can think of now is something like this :if (field.getName().equals("ABC")){ String ABC_New[]=(String[])field; ... then use ABC_New[] ...}But it won't work, what's the correct way to do it ?
Frank