3

I'm just starting to learn reflection and to do so I have a little Math app. The program wraps a logic class, and at runtime looks through the logic class it wraps for methods (in this case, add, subtract, multiply, and divide). The methods look like the one below.

public int add(int... args){
   int result = 0;
   for(int i=0;i<args.length;i++){
        result+=args[i];
   }
   return  result;
}

As you can see, this method (all the other ones do as well) takes in int... args, so I can pass in any number of ints to add together.

I then attempt to solve the Math question like so

int[] params = new int[numinputs];
//populate params with what numbers the user types in.
int result = (Integer) methodToCall.invoke(logicInstance, params);

If i call it this way, I get an IllegalArguementException on invoke().

So I guess the tl:dr is :

How do I call invoke() if the method being invoked takes in a params instead of a hardcoded number of parameters.

Thanks :)

Josh Monks
  • 129
  • 1
  • 2
  • 9
  • `varargs` compiles to bytecode where the method has one argument: an array of integers. The compiler is just nice enough to replace all variable-argument calls to the method with an implicit array creation. So, you should find the method by the one that takes a single _array_ of integers – Colin M Jul 15 '13 at 13:46
  • If methodToCall actually points to the right method, your code should run fine. What do you get if you try `System.out.println(methodToCall.toString());`? – jarnbjo Jul 15 '13 at 13:52
  • @jarnbjo No, if `methodToCall` points to the right method, he should be doing: `methodToCall.invoke(logicInstance, new Object[] { params });` The second parameter to `invoke` is an array of objects, one for each parameter. At runtime, you can't pass a variable number of arguments to the method. You must pass what the bytecode expects, which is an array of integers as _the first parameter_. – Colin M Jul 15 '13 at 13:57
  • @Colin: Yes. Since Method#invoke is itself a varargs method (the signature is `Object obj, Object ... args`), `m.invoke(obj, params)` and `m.invoke(obj, new Object[] {params})` is equivalent, unless the type of params is or can be cast to Object[], which is not the case here. – jarnbjo Jul 15 '13 at 14:09
  • @jarnbjo Yes, but varargs methods are not as convenient when one of the parameters you want to pass is, itself, an array. In this particular case, you're right that it _should_ work, but only because he's using a primitive `int[]` array. If, instead, he were using `Integer` (or _anything_ which extends `Object`), he would need to explicitly wrap the varargs call in a `new Object[] { }` since anything else (such as `Integer[]`) could be cast to `Object[]` and would not be definitive. Personally, I would be explicit in this case. – Colin M Jul 15 '13 at 14:42
  • @Colin: Why do you think that the compiler only *should* follow the language specification? For all reasonable purposes, I have no doubt that it *will* and *must* follow the JLS and in this case, the code works as expected if `methodToCall` points to the right method. – jarnbjo Jul 15 '13 at 15:43
  • @jarnbjo Emphasis was on _should_ not because I don't believe that the compiler would follow the specification, but rather because I think it's a relatively poor practice to encourage. Given that one method works _only_ on primitives and the other works for all types, I personally think it best to encourage the strategy that works in all cases. However, this doesn't answer the question and I understand your perspective - but we don't need to continue this discussion further I don't believe. – Colin M Jul 15 '13 at 15:48

1 Answers1

0

try to cast to Object params

    int[] params = new int[5]

    Class<?> c = Class.forName("your class");
    Object t = c.newInstance();
    Method m = c.getMethod("add", int[].class);
    //populate params with what numbers the user types in.
    int result = (Integer) m.invoke(t,(Object) params);
mr8lu3
  • 1