Domanda

Vorrei capire cosa potrebbe succedere con invocazione di metodi arsurti variabili usando la riflessione Java. Diciamo che abbiamo un metodo semplice:

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

E vogliamo invocarlo in modo dinamico, quindi prendiamo il metodo attraverso la riflessione:

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

E passare in un array:

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

Ora, questo non sembra funzionare abbastanza come la mia intuizione avesse pensato; In particolare, mi sembra di avere varie sfumature di IllegalArgumentException Quando provo a invocare un metodo con Vararg come questo.

C'è chiaramente qualcosa che mi manca qui. La mia ipotesi è che questo sia correlato in qualche modo a come le variabili vengono messe a marcia nei Vararg. ho trovato Questo post sul blog di quattro anni che sembra parlare dello stesso problema, ma non riesco a riprodurre il caso "riuscito" lì. Qualche idea su cosa potrebbe succedere qui?

È stato utile?

Soluzione

Devi passare in un Object[][] in questo caso:

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

Il motivo è che il singolo things Il parametro viene convertito dal compilatore in un singolo parametro di tipo Object[], e invoke prende un array con i valori dei parametri.

Considera un metodo con più parametri per renderlo più chiaro:

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

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

invoke è esso stesso dichiarato di prendere Varargs, quindi puoi lasciare che il compilatore crei l'array esterno per te. Ma non lo farà se passi un Object[], perché pensa che tu l'abbia già fatto. Quindi nascondi questo fatto al compilatore:

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

Nota il cast nella prima riga, ora il compilatore non ora non c'è più che esiste già un array, quindi ne crea uno. Nella seconda riga questo non è necessario, perché il compilatore non ha comunque altra possibilità.

Modificare: Nota che il tuo codice non si compila nemmeno perché ti sei perso un'istanza della classe con il doAllTheThings metodo a invoke (L'ho chiamato o nel mio codice).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top