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?

È stato 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:

  1. 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.
  2. Il codice dell'attaccante deve essere nello stesso pacchetto come la vostra classe interna (perché il metodo sintetico è dichiarato pacchetto-privato).
  3. 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.

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