Thursday, April 28, 2011

Use reflection to iterate over class members

I have a class with numerous parameters of various types. I want to iterate over all type A members , and run a specific functions ( A.doSomething() )

This doesn't even compile: The conversion from field to XPathDataElement is illegal

Field[] fields = this.getClass().getDeclaredFields();
  for (Field field : fields) {
     if (field. getType().getName().equals(XPathDataElement.class.getName()))
        {    
       tmp = (XPathDataElement)field; // Doesn't compile
       sb.append(field.getName() + ":"); 
       tmp.update();
     }
    }

Thanks!

From stackoverflow
  • You don't seem to assign anything to the obj that you cast to XPathDataElement in the loop.

    You probably want to do something like this:

    tmp = (XPathDataElement)field.get(this);
    
  • I strongly suggest avoiding reflection unless you really need it.

    Just write the code out:

    this.x.doSomething();
    this.y.doSomething();
    this.z.doSomething();
    

    Or if you like:

    for (A a : new A[] {
        this.x, this.y, this.z
    }) {
        a.doSomething();
    }
    
    yossale : Would you care to elaborate why I shouldn't use reflection? thanks!
    TofuBeer : you lose compile time safety, it will be a bit slower, generally you should use interfaces over reflection to ensure that things are there. Compile time safety is one of the big pluses in Java (for some it is also one of the downsides). Can you elaborate more on why you want to use reflection?
    Tom Hawtin - tackline : What TofuBear said, plus: It's more code and code which is easier to get wrong and difficult to follow. Reflection and (mobile code) security don't mix very well either.
  • It's hard to debug your code when you don't say what's wrong with it.

    Two things I can see:

    1. There's no need to compare strings to decide if the field's type is the right class.

      if (field.getType().equals(XPathDataElement.class))
      

      should work.

      Edit: Steve Reed points out that you don't necessarily need it to be exactly XPathDataElement; a subclass will work just as well. To check if the field can be treated as an XPathDataElement, you should use Class.isAssignableFrom(Class).

      if (XPathDataElement.class.isAssignableFrom(field.getType()))
      

      would be the code.

    2. I guess your real question is how to get the value of a field reflectively? If so, then Field.get(Object) is what you want. The object that you pass to get() is the one whose field you want to retrieve; if you're operating on this (which is a strong code smell), then your code would be

      XPathDataElement tmp = (XPathDataElement) field.get(this);
      
    yossale : You're absolutely right about your first comment , I've edited the post. thanks!
  • A couple of pointers:

    1. Compare the classes for equality, not their names.

      field.getType().equals(XPathDataElement.class)

    2. Or better yet, use isAssignableFrom(java.lang.Class) to handle the case where the class declares a return type as a sublclass of what you're looking for

      XPathDataElement.class.isAssignableFrom(field.getType())

    3. You're iterating over fields, not method. Your question leads me to assume you want the latter, and if so, use:

      this.getClass().getDeclaredMethods()

0 comments:

Post a Comment