Question

J'aimerais comprendre ce qui pourrait se passer lors de l'invocation de méthodes à arité variable à l'aide de la réflexion Java.Disons que nous avons une méthode simple :

void doAllTheThings(Object ... things) {
  // ...which does something with all the things...
}

Et nous voulons l'invoquer de manière dynamique, nous récupérons donc la méthode par réflexion :

Method doItAll = Superklass.getDeclaredMethod("doAllTheThings", Object[].class);

Et passez dans un tableau :

Object[] allTheThings = new Object[] { "abc", true, 15 };
doItAll.invoke(allTheThings);

Maintenant, cela ne semble pas fonctionner tout à fait comme mon intuition l’avait imaginé ;en particulier, il me semble avoir différentes nuances de IllegalArgumentException quand j'essaie d'invoquer une méthode avec des varargs comme celui-ci.

Il y a clairement quelque chose qui me manque ici.Je suppose que cela est lié d'une manière ou d'une autre à la façon dont les variables sont rassemblées dans les varargs.J'ai trouvé ce billet de blog vieux de quatre ans qui semble parler du même problème, mais je suis incapable de reproduire ici le cas « réussi ».Des idées sur ce qui pourrait se passer ici ?

Était-ce utile?

La solution

Vous devez passer dans un Object[][] dans ce cas:

Object[] allTheThings = new Object[] { "abc", true, 15 };
doItAll.invoke(o, new Object[]{allTheThings});

La raison est que le single things Le paramètre est converti par le compilateur en un seul paramètre de type Object[], et invoke prend un tableau avec les valeurs des paramètres.

Envisagez une méthode avec plus de paramètres pour que ce soit plus clair :

void doMoreThings(Foo bar, Object ... things) { ... }

Object[] allTheThings = new Object[] { "abc", true, 15 };
doMore.invoke(o, new Object[]{new Foo(), allTheThings});

invoke est lui-même déclaré prendre des varargs, vous pouvez donc laisser le compilateur créer le tableau externe pour vous.Mais il ne le fera pas si vous réussissez un Object[], car il pense que vous l'avez déjà fait.Alors cachez simplement ce fait au compilateur :

doItAll.invoke(o, (Object)allTheThings);
doMore.invoke(o, new Foo(), allTheThings);

Notez le transtypage dans la première ligne, maintenant le compilateur ne sait plus qu'il existe déjà un tableau, il en crée donc un.Dans la deuxième ligne, cela n'est pas nécessaire, car le compilateur n'a de toute façon aucune autre chance.

Modifier:Notez que votre code ne se compile même pas car vous avez manqué de transmettre une instance de la classe avec le doAllTheThings méthode pour invoke (je l'ai nommé o dans mon code).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top