views:

1390

answers:

6

Hi, I wish to initialize an array of java methods in the child class, as a class field like so

void callme() {System.out.println("hi!");}
Method[] actions = new Method[] {&callme,&callme};

and call all methods in this array at parent class like so:

for (meth:actions) {meth.invoke();}

However currently I cannot find a way to implicitly initialize the actions array, not through the constructor. The following gives me an error due to unhandled exception:

Method[] actions = new Method[] {
    this.getClass().getDeclaredMethod("count")
};

As said, I cannot catch the exception when initializing this array explicitly as a field, and not in the constructor.

I'm a newbie to java reflection, so this is probably an obvious question, still I found no answer to that at google, any help would be appreciated.

Thanks

P.S.

As Scott below guessed, I "want a superclass to call a specific set of methods defined in a subclass".

+1  A: 

Check out the Apache Commons - Beanutils! It's like a wrapper around all the reflection which is very easy to use. It wraps method invocation, modify attributes, lookups...

If you want to bring in dynamic to Java, you should have a look a dynamic JVM languages which can be used by simple including a .jar library! On of them is Groovy which contains the java syntax and bring in a lot of dynamic functionality (scripting, rapid-prototyping, Meta-Object-Protocol, runtime-method repacement, dynamic proxies...).

Martin K.
+3  A: 

Are you sure reflection is the right thing to do? Normally an interface with several anonymous classes implementing it would be better style.

You can write an initializer block to be able to catch the exception during initialization.

Why don't you use getMethod()?

starblue
A: 

Create a static method in your class which will return an array of declared methods and do the correct handling of exceptions.

private static Method[] declaredMethods(Class<T> clazz, String methodName) {
  Method[] result = new Method[1];
  try{
    result[0] = clazz.getDeclaredMethod(methodName);
  } catch (NoSuchMethodException nsme) {
    // respond to the error
  } catch (SecurityException se)  {
    // Respond to the error
  }

  return result;
}

Method[] actions = declaredMethods("count");
Boris Pavlović
That would work, but this is as ugly as... well, as ugly as Java sometimes is ;-)
Elazar Leibovich
Nobody can stop you declaring the static method declareMethods(Class<T> clazz, String) in separate class with a private constructor and hide all the ugly details. Even better you can use some Apache Commons library.
Boris Pavlović
"Respond to the error"???
Tom Hawtin - tackline
You could make methodName a varargs.
Peter Lawrey
A: 

This should work as long, as your method is really declared in in the this.getClass(). If it is inherited, you should use Class.getMethod() instead.

However, instead of using function pointers, in java one would define an interface with a method one want to call, and let that interface be implemented by the target object.

Also consider using ArrayList, or other collection classes instead of arrays.

siddhadev
+3  A: 

[Note: code below has not been compiled but should get the idea across]

I should echo -- what are you trying to accomplish?

If you want a superclass to call a specific set of methods defined in a subclass, you can do a few things.

With reflection, I'd recommend using annotations:

1) define an annotation HeySuperclassCallMe (make sure retention is RUNTIME)

2) annotate the methods to call with HeySuperclassCallMe

@HeySuperclassCallMe public void foo...

3) in your superclass do something like

for (Method m : getClass().getMethods())
  if (m.getAnnotation(HeySuperclassCallMe.class) != null)
     m.invoke(...)

That's a nice reflective means to do it.

For non-reflection (which should be a bit faster, but more code):

1) define an interface that represents the calls

 public interface Call {
     void go();
 }

2) in your superclass, define a

 private List<Call> calls
 protected void addCall(Call call)

3) in the subclass, use addCall:

 addCall(new Call() {public void go() {foo();}} );

4) in the superclass

 for (Call call : calls)
    call.go();
Scott Stanchfield
I thought of the annotation technique, but what I don't like about it is, that you can't specify the order.Actually I eventually did @UseMessage(order=0). Which worked fine, but is UGLY UGLY UGLY. (and harder to maintain, as one can't easily inseret a method in between).
Elazar Leibovich
BTW: If you name the attribute "value" you can use it without the attribute name: @UseMessage(0). Not that that helps the ordering, though.
Scott Stanchfield
A: 

I can tell by your ampersands that you are thinking in C. We don't really use pointers to functions in java.

Generally, you would not use java reflection for this. As one of the other posters said - you would create an interface, and have objects that implemented that interface - either by directly implementing it, or with an adapter or anonymous class:

interface Callable { void callme(); }

Callable[] foo = new Callable[] {
  new Callable() { public void callme() {System.out.println("foo!");}},
  new Callable() { public void callme() {System.out.println("bar!");}}
};

for(Callable c: foo) {
  c.callme();
}
paulmurray