tags:

views:

160

answers:

7

Is it possible to obtain references to an object's methods? For example, I'd like to have a method that invokes other methods as callbacks. Something like:

public class Whatever
{
  public void myMethod(Method m,Object args[])
  {

  }
}

Is this possible?

EDIT: I meant an object's methods. I take it it's not possible?

+4  A: 

Java 7 will have closures which will let you do this.

Until this is available you have two options

  • Hold a reference to an interface with a known method on and call that
  • Use reflection to call the method.
Robert Christie
Java 7 will also have method handles, which are even more direct. :-P
Chris Jester-Young
What about C#-style delegates? Are we getting those anytime?
Seva Alekseyev
Did closures make it through Java 7?
OscarRyz
@cb160: Java7 *may* have closures, it's by no means certain yet. Looks hopeful at this point, though.
skaffman
@skaffman: Although nothing is certain, Mark Reinhold, the Project Lead for JDK7 announced at Devoxx 09 that Sun would be developing closures for inclusion in JDK7 - http://blogs.sun.com/mr/entry/closures
Robert Christie
Java 1.1 has (verbose) closures.
Tom Hawtin - tackline
+1  A: 

Yes, you use the reflection API, for example java.lang.Class.getMethods() (and other similar methods on Class). You invoke a Method object using Method.invoke().

The reflection API is not especially nice to use, and it carries a performance penalty (although this is much less significant than it used to be), but it does the job.

skaffman
+3  A: 

Runs contrary to the design philosophy of Java. You're supposed to create a single-method class and pass around a reference to an instance of that.

Seva Alekseyev
+2  A: 

Here's an example of what's required for a callback:

public interface Callback {
  public void execute(Object[] args);
}

public class MyCallback implements Callback {
  public void execute(Object args[]) {
    System.out.println(Arrays.asList(args));
  }
}

public class Whatever {
  public void myMethod(Callback callback,Object args[]) {
    callback.execute(args);
  }
}

If you hand an instance of MyCallback into Whatever.myMethod, it will print whatever you hand in as the arguments.

jamie mccrindle
A: 

Via Reflection you can get access to a Class's Methods - see

http://java.sun.com/docs/books/tutorial/reflect/member/methodInvocation.html

and

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/Method.html

However, you have to pass in an instance of that class as well as the arguments. You could create a simple wrapper class, though, something like

 class MethodInvoker{
        private Object o;
        private String methodName;
        public MethodInvoker(Object o, String methodName){
            this.o=o;
            this.methodName=methodName;
        }

        public Object invoke(Object[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{
            Class[] paramTypes = new Class[args.length];
            for(int i=0;i<paramTypes.length;i++){
                paramTypes[i] = args[i].getClass();
            }
            return o.getClass().getMethod(methodName, paramTypes).invoke(o, args);
        }
    }

Be careful, though, as this would not work with any null parameters.

Alex Vigdor
+1  A: 

Although it's possible through reflection, the much better bet is to pass an object and access it through an interface the way sorting currently works (passing in an comparator). Getting in the habit of thinking and designing this way is the start of actually understanding OO programming.

Doing it through method references leads towards worse overall design--But is obviously easier for a quick one-off hack job. If you are happy with hacking just use Groovy instead where all those short-cuts are built in and have a much reduced/simplified syntax just designed for quick disposable code instead of long-term maintenance.

Bill K
+1  A: 

Yes, it is possible.

You just have the get the method and invoke it.

Here's some sample code:

$cat InvokeMethod.java  
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

public class InvokeMethod {

    public static void invokeMethod( Method m , Object o ,  Object ... args )  
    throws IllegalAccessException, 
           InvocationTargetException {

        m.invoke( o, args );

    }

    public static void main( String [] args ) 
    throws NoSuchMethodException,
           IllegalAccessException,
           InvocationTargetException {

         SomeObject object = new SomeObject();
         Method method = object.getClass().getDeclaredMethod( "someMethod",  String.class );
         invokeMethod( method, object, "World");

    }
}

class SomeObject {
    public void someMethod( String name ){
        System.out.println( "    Hello " + name );
    }
}
$javac InvokeMethod.java 
$java InvokeMethod
Hello World
$

Now the question is, what are you trying to do? perhaps are better ways. But as for your question the answer is YES.

OscarRyz