# Create callback

**URL:** <https://discourse.processing.org/t/create-callback/9831>\
**Category:** Coding Questions\
**Created:** [April 1, 2019, 10:20am UTC](https://discourse.processing.org/t/create-callback/9831 "2019-04-01T10:20:46Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 1, 2019, 10:20am UTC](https://discourse.processing.org/t/create-callback/9831/1 "2019-04-01T10:20:46Z")

</div>

I try to create a method to make a callback, but that’s don’t work. Consol return the error message. I think my problem is from: i pass `this` and this don’t read my sketch i suppose ?

```auto
void setup() {
  select_callback("my_method",this);
}

import java.lang.reflect.Method;
void select_callback(String callbackMethod, Object callbackObject) {
  try {
    Class<?> callbackClass = callbackObject.getClass();
    Method selectMethod =
    callbackClass.getMethod(callbackMethod, new Class[] { File.class });
  } catch(NoSuchMethodException nsme) {
    System.err.println(callbackMethod + "() could not be found");
  }
  
}

void my_method() {
  println("truc");
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 1, 2019, 12:14pm UTC](https://discourse.processing.org/t/create-callback/9831/2 "2019-04-01T12:14:40Z")

</div>

> [@Stanlepunk](#):
>
> `callbackClass.getMethod(callbackMethod, new Class[] { File.class });`

It’s attempting to find a method of name “my\_method” from class PApplet that has 1 parameter of datatype File. 🗄

However, PApplet::**my\_method()** is parameterless! 🙄

> [@Stanlepunk](#):
>
> ```auto
> void my_method() {
> println("truc");
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 1, 2019, 12:47pm UTC](https://discourse.processing.org/t/create-callback/9831/3 "2019-04-01T12:47:21Z")

</div>

> [@GoToLoop](#):
>
> PApplet:: **my\_method()**

what is it? I don’t underwant what you mean by parameterless ? You mean there is possibility, if yes how do that ?

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [April 1, 2019, 1:06pm UTC](https://discourse.processing.org/t/create-callback/9831/4 "2019-04-01T13:06:42Z")

</div>

> [@Stanlepunk](#):
>
> void my\_method() { println(“truc”); }

Should be

```auto
void my_method(File file) {
 println("truc");
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 1, 2019, 1:33pm UTC](https://discourse.processing.org/t/create-callback/9831/5 "2019-04-01T13:33:23Z")

</div>

> [@Stanlepunk](#):
>
> What is it?

PApplet::**my\_method()** means an instance method named **my\_method()** of datatype PApplet.

> [@Stanlepunk](#):
>
> I don’t understand what you mean by parameterless?

Parameters are variables declared inside a function’s `()` parens which receive passed arguments.

A parameterless function is simply a function w/ an empty `()` parens.

[en.Wiktionary.org/wiki/parameterless](http://en.Wiktionary.org/wiki/parameterless)

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 1, 2019, 3:12pm UTC](https://discourse.processing.org/t/create-callback/9831/6 "2019-04-01T15:12:27Z")

</div>

@quark @GoToLoop thks for your lights !  
Et voilà the result:

```auto
void setup() {
}

int count = 0;
void draw() {
  count++;
  select_callback("my_method",this,"truc", count);
}

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
void select_callback(String callbackMethod, Object callbackObject, String s, int i) {
  try {
    Class<?> callbackClass = callbackObject.getClass();
    Method selectMethod =
    callbackClass.getMethod(callbackMethod, 
                            new Class[] { String.class, int.class });
                            
    selectMethod.invoke(callbackObject, s,i);
  } catch (IllegalAccessException iae) {
      System.err.println(callbackMethod + "() must be public");

  } catch (InvocationTargetException ite) {
      ite.printStackTrace();

  } catch (NoSuchMethodException nsme) {
      System.err.println(callbackMethod + "() could not be found");
    }
}

void my_method(String stuff, int value) {
  println(stuff,value);
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 1, 2019, 4:04pm UTC](https://discourse.processing.org/t/create-callback/9831/7 "2019-04-01T16:04:05Z")

</div>

> [@Stanlepunk](#):
>
> `new Class[] { String.class, int.class });`

Method::**getMethod()**'s 2nd parameter is [variadic](https://en.wiktionary.org/wiki/variadic). So you don’t need to instantiate an array for it:  
`callbackClass.getMethod(callbackMethod, String.class, int.class);`

And no need to 3 `catch ()` blocks. This 1 deals w/ all of them:  
`} catch (final ReflectiveOperationException e) {`

[Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ReflectiveOperationException.html](http://Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ReflectiveOperationException.html)

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 3, 2019, 2:07pm UTC](https://discourse.processing.org/t/create-callback/9831/8 "2019-04-03T14:07:40Z")

</div>

Thx but I don’t understand what you mean… may be if you rewrite my code is more understandable. Because for my my code work nice, And don’t see where I instantiate an array, plus I don’ understand too why my secend argument is variadic or not comparable… sorry for my missing knowledge !!!

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [April 3, 2019, 6:48pm UTC](https://discourse.processing.org/t/create-callback/9831/9 "2019-04-03T18:48:24Z")

</div>

GoToLoop is providing _alternative code to do the same job_, whether you use it or not is up to you. There is little to choose between them.

Personally I would stick with the style you are using, there are some benefits to instantiating a `Class` array to hold the parameter types and separating the catch clauses gives you the option to treat the exceptions differently.

> [@Stanlepunk](#):
>
> Because for my my code work nice

Yes it works but it has one serious flaw, the draw() method is executed 60 times a second but you only need to find the method once.

In the example sketch below I have modified your code so that the method is found in setup and then invoked in draw. It also shows how to find methods without parameters.

```auto
import java.lang.reflect.*;

Method method_1 = null;
Method method_2 = null;

void setup() {
  // Find a callback with 2 parameters
  method_1 = select_callback("my_method_1", this, new Class[] {String.class, int.class} );
  // Find a callback with no parameters
  method_2 = select_callback("my_method_2", this, new Class[0]);
}

int count = 0;

void draw() {
  count++;
  try {
    method_1.invoke(this, "truc", count);
  } 
  catch (IllegalAccessException iae) {
    System.err.println(method_1.getName() + "() must be public");
  }
  catch (InvocationTargetException ite) {
    System.err.println("The method " + method_1.getName() + "() threw an exception");
    ite.printStackTrace();
  }

  try {
    method_2.invoke(this);
  } 
  catch (IllegalAccessException iae) {
    System.err.println(method_1.getName() + "() must be public");
  }
  catch (InvocationTargetException ite) {
    System.err.println("The method " + method_1.getName() + "() threw an exception");
    ite.printStackTrace();
  }
}

/**
 Find a method matching the parameters
 @parameter callbackMethod the name of the callback method
 @parameter callbackObject the object resposible for executing the calback
 @parameter params an array of classes of the parametrs for the call back method
 */
Method select_callback(String callbackMethod, Object callbackObject, Class... params) {
  Method callback = null;
  try {
    Class<?> callbackClass = callbackObject.getClass();
    callback = callbackClass.getMethod(callbackMethod, params );
  } 
  catch (NoSuchMethodException nsme) {
    System.err.println(callbackMethod + "() could not be found");
  }  
  return callback;
}

void my_method_1(String stuff, int value) {
  println(stuff, value);
}

void my_method_2() {
  println("============================");
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 3, 2019, 7:44pm UTC](https://discourse.processing.org/t/create-callback/9831/10 "2019-04-03T19:44:12Z")

</div>

Oh, I was doing almost the same too: 😞

```java
/**
 * Method Reflective Invocation (v3.0)
 * Stanlepunk (2019/Apr/03)
 * Mod GoToLoop
 * https://Discourse.Processing.org/t/create-callback/9831/10
 */

import java.lang.reflect.Method;
final Method myMethod = getStrIntMethod("myMethod", this);

void setup() {
  frameRate(1);
}

void draw() {
  background((color) random(#000000));
  invokeStrIntMethod(myMethod, this, "Frames:", frameCount);
}

static final void myMethod(final String stuff, final int num) {
  println(stuff, num);
}

static final Method getStrIntMethod(final String name, final Object instance) {
  final Class<?> c = instance.getClass();

  try {
    return c.getMethod(name, String.class, int.class);
  } 
  catch (final NoSuchMethodException e) {
    try {
      final Method m = c.getDeclaredMethod(name, String.class, int.class);
      m.setAccessible(true);
      return m;
    }   
    catch (final NoSuchMethodException ex) {
      ex.printStackTrace();
      return null;
    }
  }
}

static final void invokeStrIntMethod(
  final Method funct, final Object instance, final String txt, final int val) {
  try {
    funct.invoke(instance, txt, val);
  } 
  catch (final ReflectiveOperationException e) {
    e.printStackTrace();
  }
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 3, 2019, 7:58pm UTC](https://discourse.processing.org/t/create-callback/9831/11 "2019-04-03T19:58:58Z")

</div>

> [@quark](#):
>
> , there are some benefits to instantiating a Class array to hold the parameter types…

Which 1s? Unless we’re also storing the array to use it later, there’s ZERO benefit! 🙄

Should we create an Object array for Method::**invoke()** as well? 🤭

`method_1.invoke(this, "truc", count);` ➡  
`method_1.invoke(this, new Object[] { "truc", count });`

Both Class::**getMethod()** & Method::**invoke()** got variadic args.

But you’re advocating an array for: Class::**getMethod()**: 🤔  
`method_1 = select_callback("my_method_1", this, new Class[] {String.class, int.class} );`

And not for: Method::**invoke()**? 🤪  
`method_1.invoke(this, "truc", count);`

> [@quark](#):
>
> … and separating the `catch ()` clauses gives you the option to treat the exceptions differently.

Yea, for the ultra rare cases indeed. But it’s none of our cases here! 😳

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 3, 2019, 8:09pm UTC](https://discourse.processing.org/t/create-callback/9831/12 "2019-04-03T20:09:00Z")

</div>

> [@quark](#):
>
> It also shows how to find methods without parameters.

For such cases PApplet class already got a method called **method()**: 👼  
[Processing.GitHub.io/processing-javadocs/core/processing/core/PApplet.html#method-java.lang.String-](http://Processing.GitHub.io/processing-javadocs/core/processing/core/PApplet.html#method-java.lang.String-)

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 4, 2019, 12:54pm UTC](https://discourse.processing.org/t/create-callback/9831/13 "2019-04-04T12:54:16Z")

</div>

@quark @GoToLoop nice no I4ve three ways to make the same thing. I’ll study your algo to understand well how that’s work. thanks a lot.

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 4, 2019, 1:06pm UTC](https://discourse.processing.org/t/create-callback/9831/14 "2019-04-04T13:06:54Z")

</div>

The good point here : there is only one instantiating and after no need to rebuild, juste use. But the problem you must right the in code the method name. With mine the name can be pass with a String and it’s what i need. So I think try to rewrite your code to use in this way.

thx

> [@quark](#):
>
> Method method\_1 = null; Method method\_2 = null;

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 4, 2019, 1:18pm UTC](https://discourse.processing.org/t/create-callback/9831/15 "2019-04-04T13:18:33Z")

</div>

I’ve a feeling for there is a same issue than @quark code it’s necessary to write a method before this one exist, or like as usual i’m weong ?

> [@GoToLoop](#):
>
> final Method myMethod = getStrIntMethod(“myMethod”, this);

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 4, 2019, 1:33pm UTC](https://discourse.processing.org/t/create-callback/9831/16 "2019-04-04T13:33:04Z")

</div>

You can call **getStrIntMethod()** from anywhere, as long as you have access to the “myMethod”'s object instance reference. 🕶

BtW, here’s a more powerful generic version, which can find & invoke any method name w/ any number of parameters & types: 🥳

```java
/**
 * Method Reflective Invocation (v4.0)
 * Stanlepunk (2019/Apr/03)
 * Mod GoToLoop
 * https://Discourse.Processing.org/t/create-callback/9831/16
 */

import java.lang.reflect.Method;
final Method myMethod = getMethod("myMethod", this, String.class, int.class);

void setup() {
  frameRate(1);
}

void draw() {
  background((color) random(#000000));
  invokeMethod(myMethod, this, "Frames:", frameCount);
}

static final void myMethod(final String stuff, final int num) {
  println(stuff, num);
}

@SafeVarargs static final Method getMethod(
  final String name, final Object instance, final Class... classes) {
  final Class<?> c = instance.getClass();

  try {
    return c.getMethod(name, classes);
  } 
  catch (final NoSuchMethodException e) {
    try {
      final Method m = c.getDeclaredMethod(name, classes);
      m.setAccessible(true);
      return m;
    }   
    catch (final NoSuchMethodException ex) {
      ex.printStackTrace();
      return null;
    }
  }
}

@SafeVarargs static final Object invokeMethod(
  final Method funct, final Object instance, final Object... args) {
  try {
    return funct.invoke(instance, args);
  } 
  catch (final ReflectiveOperationException e) {
    throw new RuntimeException(e);
  }
}

```

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 4, 2019, 1:55pm UTC](https://discourse.processing.org/t/create-callback/9831/17 "2019-04-04T13:55:08Z")

</div>

Whatthe utility of `@SafeVarargs`

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 4, 2019, 1:56pm UTC](https://discourse.processing.org/t/create-callback/9831/18 "2019-04-04T13:56:23Z")

</div>

[Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/SafeVarargs.html](http://Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/SafeVarargs.html)

---

<div class="post-metadata">

**Author:** ![Stanlepunk](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/stanlepunk/32/11509_2.png) [@Stanlepunk](https://discourse.processing.org/u/Stanlepunk)\
**Post date:** [April 5, 2019, 10:33am UTC](https://discourse.processing.org/t/create-callback/9831/19 "2019-04-05T10:33:35Z")

</div>

Et voilà, a method manager, to create method, add in a list of method and to call it with String name and check if this one already existe. I don’t if it’s really optimizing but that’s work 🙂

```auto
/**
* Manage creator method
*/
void setup() {
  frameRate(1);
  create_method("my_method",this, String.class, int.class);
  create_method("my_method",this, String.class, int.class); // print: create_method(): this method my_method with those classes organisation already exist
  create_method("my_method",this, String.class, int.class, float.class);
  println("method size:",method_index.size());
  for(Method_Manager mm : method_index) {
    println(mm.get_name());
    printArray(mm.get_index());
  }
}

void draw() {
  surface.setTitle(Integer.toString((int)frameRate));
  background((int)random(#000000));
  method("my_method",this,"Frames:", frameCount);
  method("my_method",this,"Frames:", frameCount, 3.4);
  //method("my_method",this,"Frames:", frameCount);
}

void my_method(final String stuff, final int num) {
  println(stuff, num);
}

/**
* Method manager to call method if this one already exist
* v 0.0.1
* 2019-2019
*/
void method(String name, PApplet pa, Object... args) {
  Method method = method_exist(name, args);
  if(method != null) {
    invoke_method(method, pa, args);
  } else {
    println("method(): no method exist for this name:",name,"or this order of arguments:");
    for(int i = 0 ; i < args.length ; i++) {
      println("[",i,"]",args[i].getClass().getName());
    } 
  }
}

Method method_exist(String name, Object... args) {
  Method method = null;
  if(method_index != null && method_index.size() > 0) {
    for(Method_Manager mm : method_index) {
      if(mm.get_name().equals(name)) {
        boolean same_is = true;
        if(args.length == mm.get_index().length) {
          for(int i = 0 ; i < args.length; i++) {
            String arg_name = translate_class_to_type_name_if_necessary(args[i]);
            if(!arg_name.equals(mm.get_index()[i])) {
              same_is = false;
              break;
            }
          }
        } else {
          same_is = false;
        }       
        if(same_is) {
          method = mm.get_method();
        }
      }
    }
  }
  return method;
}

String translate_class_to_type_name_if_necessary(Object arg) {
  String name = arg.getClass().getName();
  if(name.equals("java.lang.Byte")) {
    name = "byte";
  } else if(name.equals("java.lang.Short")) {
    name = "short";
  } else if(name.equals("java.lang.Integer")) {
    name = "int";
  } else if(name.equals("java.lang.Long")) {
    name = "long";
  } else if(name.equals("java.lang.Float")) {
    name = "float";
  } else if(name.equals("java.lang.Double")) {
    name = "double";
  } else if(name.equals("java.lang.Boolean")) {
    name = "boolean";
  } else if(name.equals("java.lang.Character")) {
    name = "char";
  }
  return name;
}

void create_method(String name, PApplet pa, Class... classes) {
  if(method_index == null) {
    method_index = new ArrayList<Method_Manager>();
  } 
  init_method(name,pa,classes);
}

ArrayList<Method_Manager> method_index ;
void init_method(String name, PApplet pa, Class... classes) { 
  // check if method already exist
  boolean create_class_is = true; 
  for(Method_Manager mm : method_index) {
    if(mm.get_name().equals(name)) {
      if(mm.get_index().length == classes.length) {
        int count_same_classes = 0;
        for(int i = 0 ; i < classes.length ; i++) {
          if(mm.get_index()[i].equals(classes[i].getCanonicalName())) {
            count_same_classes++;
          }
        }
        if(count_same_classes == classes.length) {
          create_class_is = false;
          break;
        }
      }
    }
  }
  // instantiate if necessary
  if(create_class_is) {
    Method method = get_method(name,pa,classes);
    Method_Manager method_manager = new Method_Manager(method,name,classes);
    method_index.add(method_manager);
  } else {
    println("create_method(): this method",name,"with those classes organisation already exist");
  }
}

/**
* Method manger
*/
import java.lang.reflect.Method;
class Method_Manager {
  Method method;
  String name;
  String [] index;
  Method_Manager(Method method, String name, Class... classes) {
    index = new String[classes.length];
    for(int i = 0 ; i < index.length ; i++) {
      index[i] = classes[i].getName();
    }
    this.method = method;
    this.name = name;
  }

  String [] get_index() {
    return index;
  }

  String get_name() {
    return name;
  }

  Method get_method() {
    return method;
  }
}

/**
 * refactoring of Method Reflective Invocation (v4.0)
 * Stanlepunk (2019/Apr/03)
 * Mod GoToLoop
 * https://Discourse.Processing.org/t/create-callback/9831/16
 */
static final Method get_method(String name, Object instance, Class... classes) {
  final Class<?> c = instance.getClass();
  try {
    return c.getMethod(name, classes);
  } 
  catch (final NoSuchMethodException e) {
    try {
      final Method m = c.getDeclaredMethod(name, classes);
      m.setAccessible(true);
      return m;
    }   
    catch (final NoSuchMethodException ex) {
      ex.printStackTrace();
      return null;
    }
  }
}

static final Object invoke_method(Method funct, Object instance, Object... args) {
  try {
    return funct.invoke(instance, args);
  } 
  catch (final ReflectiveOperationException e) {
    throw new RuntimeException(e);
  }
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [April 5, 2019, 11:53am UTC](https://discourse.processing.org/t/create-callback/9831/20 "2019-04-05T11:53:55Z")

</div>

If you need to know whether 2 Method objects represent the same actual method, just call **equals()** on 1 of the objects in order to compare them. 💡

You can also call **getParameterTypes()** to get an array of classes of the Method’s parameter types: 😸

[Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Executable.html#getParameterTypes()](http://Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Executable.html#getParameterTypes())

```java
// https://Discourse.Processing.org/t/create-callback/9831/20
// GoToLoop (2019/Apr/05)

import java.lang.reflect.Method;

final Method[] methods = {
  getMethod("myMethod", this, String.class, int.class), 
  getMethod("myMethod", this, String.class, int.class), 
  getMethod("myMethod", this, String.class, int.class, float.class)
};

void setup() {
  println(methods[0] == methods[1]); // we can't use the compare == operator!
  println(methods[0].equals(methods[1])); // true
  println(methods[0].equals(methods[2])); // false

  for (final Method m : methods) {
    println();
    printArray(m.getParameterTypes());
  }

  exit();
}

static final void myMethod(final String stuff, final int num) {
  println(stuff, num);
}

static final void myMethod(final String stuff, final int num, float frac) {
  println(stuff, num);
}

@SafeVarargs static final Method getMethod(
  final String name, final Object instance, final Class... classes) {
  final Class<?> c = instance.getClass();

  try {
    return c.getMethod(name, classes);
  } 
  catch (final NoSuchMethodException e) {
    try {
      final Method m = c.getDeclaredMethod(name, classes);
      m.setAccessible(true);
      return m;
    }   
    catch (final NoSuchMethodException ex) {
      ex.printStackTrace();
      return null;
    }
  }
}

```

[Next page](https://discourse.processing.org/t/create-callback/9831.md?page=2)
