Quali sono gli interessi dei metodi di sintesi?
-
20-09-2019 - |
Domanda
problema
Un amico ha suggerito un problema interessante. Dato il seguente codice:
public class OuterClass {
private String message = "Hello World";
private class InnerClass {
private String getMessage() {
return message;
}
}
}
Da una classe esterna, come posso stampare il contenuto variabile message
? Naturalmente, cambiando l'accessibilità di metodi o campi è non permesso.
( qui , ma si tratta di un blog francese)
Soluzione
Il codice per risolvere questo problema è il seguente:
try {
Method m = OuterClass.class.getDeclaredMethod("access$000", OuterClass.class);
OuterClass outerClass = new OuterClass();
System.out.println(m.invoke(outerClass, outerClass));
} catch (Exception e) {
e.printStackTrace();
}
Si noti che il nome del metodo access$000
in realtà non è standard (anche se questo formato è quello che è fortemente recommanded ), e alcuni JVM nominerà questo metodo access$0
. Così, una soluzione migliore è quella di verificare la presenza di metodi di sintesi:
Method method = null;
int i = 0;
while ((method == null) && (i < OuterClass.class.getDeclaredMethods().length)) {
if (OuterClass.class.getDeclaredMethods()[i].isSynthetic()) {
method = OuterClass.class.getDeclaredMethods()[i];
}
i++;
}
if (method != null) {
try {
System.out.println(method.invoke(null, new OuterClass()));
} catch (Exception e) {
e.printStackTrace();
}
}
Dunque, il punto interessante in questo problema è quello di evidenziare l'uso di metodi di sintesi. Con questi metodi, posso accedere a un campo privato, come è stato fatto nella soluzione. Naturalmente, ho bisogno di utilizzare la riflessione, e penso che l'uso di questo genere di cose può essere molto pericoloso ...
Domanda
Qual è l'interesse - per me, come sviluppatore - di un metodo sintetico? Che cosa può essere una buona situazione in cui utilizza il sintetico può essere utile?
Soluzione
Come si dimostra, modificatori di accesso Java sono puramente informativi, e possono essere aggirate utilizzando riflessione. Così le vostre domande è più o meno equivalente a "qual è l'interesse di eludere un modificatore di accesso?" Oltre a scopi dannosi, debug viene in mente; si potrebbe ad esempio registrare lo stato interno dei meccanismi interni di alcuni della biblioteca da fuori la biblioteca, senza dover toccare il codice libreria stessa a tutti. Un altro esempio è collaborazione con linguaggi di scripting ; se non sapete in fase di compilazione, che sono disponibili classi e metodi, la riflessione può essere molto utile. Per esempio, Jython interni s 'utilizza enormi quantità di riflessione intorno.
Altri suggerimenti
Qual è l'interesse - per voi, come sviluppatore - di un metodo sintetico? Beh, per cominciare, non li invocare (per ragioni diverse answerers hanno spiegato).
Ma c'è una cosa interessante da tenere a mente, soprattutto se si sta scrivendo codice Java per l'esecuzione in un ambiente sensibile alla sicurezza, e questo è che i metodi sintetici possono potenzialmente fornire attaccanti un back-porta per i vostri campi privati.
Naturalmente, ci sono alcuni grandi "se" - voglio dire, le condizioni necessarie - per una tale vulnerabilità alla realtà importa:
- L'attaccante è in realtà essere in esecuzione codice nel tuo JVM. La maggior parte delle volte questo non è un problema, perché l'unico codice di esecuzione è il proprio.
- Il codice dell'attaccante deve essere nello stesso pacchetto come la vostra classe interna (perché il metodo sintetico è dichiarato pacchetto-privato).
- Il codice dell'attaccante deve essere caricato dallo stesso classloader come la vostra classe. Se si sta lasciando il codice non attendibile per l'esecuzione in JVM (condizione # 1), allora è meglio usare un programma di caricamento classe separata per il codice non attendibile.
Non si dovrebbe mai invocare metodi accessori di sintesi utilizzando la riflessione, sono passibili di modifica, a seconda di quale compilatore si utilizza. Ad esempio, in esecuzione la vostra soluzione su jdk1.6 sulla mia macchina non è riuscita, in quanto il metodo access$000
non è stato trovato.
di accesso sintetici sono un sotto-il-copre compilatore trucco per aggirare il fatto che le classi interne erano un'aggiunta a Java 1.1, e la specifica VM era mai cambiato per accoglierli.