java works Cos'è la riflessione e perché è utile?




reflection java stackoverflow (14)

Reflection è la capacità di una lingua di ispezionare e richiamare dinamicamente classi, metodi, attributi, ecc. In fase di esecuzione.

Ad esempio, tutti gli oggetti in Java hanno il metodo getClass() , che consente di determinare la classe dell'oggetto anche se non lo si conosce in fase di compilazione (ad esempio se lo hai dichiarato come Object ) - questo potrebbe sembrare banale, ma tale la riflessione non è possibile in linguaggi meno dinamici come il C++ . Usi più avanzati ti consentono di elencare e chiamare metodi, costruttori, ecc.

La riflessione è importante poiché consente di scrivere programmi che non devono "sapere" tutto in fase di compilazione, rendendoli più dinamici, poiché possono essere collegati insieme in fase di runtime. Il codice può essere scritto su interfacce note, ma le classi effettive da utilizzare possono essere istanziate utilizzando il reflection dai file di configurazione.

Un sacco di strutture moderne usano ampiamente la riflessione proprio per questo motivo. La maggior parte degli altri linguaggi moderni usa anche la riflessione, e nei linguaggi di scripting (come Python) sono ancora più strettamente integrati, poiché è più naturale nel modello di programmazione generale di quelle lingue.

https://code.i-harness.com

Cos'è la riflessione e perché è utile?

Sono particolarmente interessato a Java, ma presumo che i principi siano gli stessi in qualsiasi lingua.


Come suggerisce il nome stesso, esso riflette ciò che contiene, ad esempio il metodo di classe, ecc. Oltre a fornire funzionalità per invocare il metodo creando istanze dinamicamente in fase di runtime.

È usato da molti framework e applicazioni sotto il legno per invocare servizi senza conoscere realmente il codice.


Esempio :
Prendi ad esempio un'applicazione remota che assegna alla tua applicazione un oggetto che ottieni usando i loro metodi API. Ora, in base all'oggetto, potrebbe essere necessario eseguire una sorta di calcolo.
Il provider garantisce che l'oggetto può essere di 3 tipi e dobbiamo eseguire calcoli in base al tipo di oggetto.
Quindi potremmo implementare in 3 classi ognuna contenente una logica diversa. Ovviamente le informazioni sull'oggetto sono disponibili in runtime, quindi non è possibile codice statico per eseguire la computazione, quindi la riflessione viene utilizzata per istanziare l'oggetto della classe che si richiede per eseguire il calcolo basato sul oggetto ricevuto dal fornitore.


Il nome reflection è usato per descrivere il codice che è in grado di ispezionare altro codice nello stesso sistema (o se stesso).

Ad esempio, supponiamo di avere un oggetto di tipo sconosciuto in Java e si desideri chiamare un metodo 'doSomething' su di esso se ne esiste uno. Il sistema di tipizzazione statico di Java non è progettato per supportare questo a meno che l'oggetto non sia conforme a un'interfaccia conosciuta, ma usando il reflection, il codice può guardare l'oggetto e scoprire se ha un metodo chiamato "doSomething" e quindi chiamarlo se volere.

Quindi, per darti un esempio di codice in Java (immagina che l'oggetto in questione sia foo):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Un caso d'uso molto comune in Java è l'uso con annotazioni. Ad esempio, JUnit 4 utilizzerà la riflessione per esaminare le classi per i metodi contrassegnati con l'annotazione @Test e quindi li chiamerà durante l'esecuzione del test dell'unità.

Ci sono alcuni buoni esempi di riflessione per iniziare a http://docs.oracle.com/javase/tutorial/reflect/index.html

E infine, sì, i concetti sono praticamente simili in altri linguaggi di tipi statici che supportano la riflessione (come C #). Nei linguaggi tipizzati dinamicamente, il caso d'uso sopra descritto è meno necessario (poiché il compilatore consente di chiamare qualsiasi metodo su qualsiasi oggetto, non funzionante in runtime se non esiste), ma il secondo caso di cercare i metodi che sono contrassegnati o lavorare in un certo modo è ancora comune.

Aggiornamento da un commento:

La possibilità di ispezionare il codice nel sistema e vedere i tipi di oggetto non è riflessione, ma piuttosto Introspezione. La riflessione è quindi la capacità di apportare modifiche in fase di esecuzione sfruttando l'introspezione. La distinzione è necessaria in quanto alcune lingue supportano l'introspezione, ma non supportano la riflessione. Uno di questi esempi è C ++


Java Reflection rende possibile ispezionare classi, interfacce, campi e metodi in fase di esecuzione, senza conoscere i nomi delle classi, dei metodi ecc. In fase di compilazione. Principalmente a livello di struttura si possono ottenere i massimi benefici della riflessione. Il codice byte che viene compilato se necessita di ulteriori modifiche in fase di esecuzione per l'esame, la modifica, l'aggiunta di più codice byte in sé o un altro programma o un altro framework a livello di metodo, livello variabile di istanza, livello costruttore, riflessione livello annotazione può essere utile.

Supponiamo di avere un metodo add(Int a,int b) . Il codice byte equivalente è supponiamo B1 . Se supponiamo di avere 1000 metodi chiamati add nel tuo sistema. Ora si desidera controllare il valore dei parametri a e b prima che venga chiamato il metodo add . Pertanto, è possibile incollare il codice su un altro programma o framework che utilizza la riflessione per esaminare dinamicamente il valore del codice byte utilizzando Object.getClass.getMethod() . Ci sono diverse classi da esaminare. Può aggiungere più operazioni prima che venga chiamato il metodo add . Ma il programma stesso o un altro programma o framework non conoscono l'oggetto che ha un metodo chiamato add . Principalmente nell'iniezione di dipendenza, l'uso della riflessione orientata all'aspetto è principalmente usato.


La riflessione è lasciare che l'oggetto veda il loro aspetto. Questo argomento non sembra avere nulla a che fare con la riflessione. In effetti, questa è l'abilità di "autoidentificazione".

La riflessione stessa è una parola per quei linguaggi che mancano della capacità di auto-conoscenza e auto-sensing come Java e C #. Poiché non hanno la capacità di auto-conoscenza, quando vogliamo osservare come appare, dobbiamo avere un'altra cosa su cui riflettere. I linguaggi dinamici eccellenti come Ruby e Python possono percepire il proprio riflesso senza l'aiuto di altri individui. Possiamo dire che l'oggetto di Java non può percepire come appare senza uno specchio, che è un oggetto della classe reflection, ma un oggetto in Python può percepirlo senza uno specchio. Ecco perché abbiamo bisogno di riflessione in Java.


Non tutte le lingue supportano la riflessione, ma i principi sono solitamente gli stessi nelle lingue che lo supportano.

La riflessione è la capacità di "riflettere" sulla struttura del tuo programma. O più concreto. Per esaminare gli oggetti e le classi che hai e ottenere informazioni a livello di codice sui metodi, i campi e le interfacce che implementano. Puoi anche guardare cose come annotazioni.

È utile in molte situazioni. Ovunque tu voglia essere in grado di collegare dinamicamente le classi al tuo codice. I lotti di mappatori relazionali di oggetti utilizzano la riflessione per essere in grado di creare un'istanza di oggetti dai database senza sapere in anticipo quali oggetti verranno utilizzati. Le architetture plug-in sono un altro luogo in cui la riflessione è utile. Essere in grado di caricare dinamicamente il codice e determinare se ci sono tipi che implementano l'interfaccia giusta da utilizzare come plugin è importante in quelle situazioni.


Reflection è un insieme di funzioni che ti permettono di accedere alle informazioni di runtime del tuo programma e modificarne il comportamento (con alcune limitazioni).

È utile perché consente di modificare il comportamento di runtime in base alle informazioni sulla meta del programma, ovvero, è possibile controllare il tipo di ritorno di una funzione e modificare il modo in cui gestisci la situazione.

Ad esempio in C # puoi caricare un assembly (un file .dll) in runtime, esaminarlo, navigare tra le classi e compiere azioni in base a ciò che hai trovato. Permette anche di creare un'istanza di una classe su runtime, invocarne il metodo, ecc.

Dove può essere utile? Non è utile sempre ma per situazioni concrete. Ad esempio, è possibile utilizzarlo per ottenere il nome della classe ai fini della registrazione, per creare dinamicamente gestori per gli eventi in base a quanto specificato in un file di configurazione e così via ...


Reflection ti dà la possibilità di scrivere più codice generico. Ti permette di creare un oggetto in runtime e chiamarne il metodo in fase di runtime. Quindi il programma può essere reso altamente parametrizzato. Permette anche di introspecting l'oggetto e la classe per rilevare le sue variabili e il metodo esposto al mondo esterno.


Secondo la mia comprensione:

Reflection consente al programmatore di accedere dinamicamente alle entità nel programma. Ad esempio, mentre codifica un'applicazione se il programmatore non è a conoscenza di una classe o dei suoi metodi, può utilizzare tale classe dinamicamente (in fase di esecuzione) utilizzando la reflection.

Viene frequentemente utilizzato in scenari in cui il nome di una classe cambia frequentemente. Se si verifica una situazione del genere, è complicato per il programmatore riscrivere l'applicazione e cambiare il nome della classe ancora e ancora.

Invece, usando la riflessione, è necessario preoccuparsi di un nome di classe che potrebbe cambiare.


Voglio solo aggiungere un punto a tutto ciò che è stato elencato.

Con Reflection API puoi scrivere il metodo universale toString() per qualsiasi oggetto.

È utile al debug.

Ecco alcuni esempi:

class ObjectAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}

semplice esempio di riflessione. In una partita a scacchi, non sai cosa verrà spostato dall'utente in fase di esecuzione. la riflessione può essere utilizzata per chiamare metodi già implementati in fase di esecuzione.

public class Test {

    public void firstMoveChoice(){
        System.out.println("First Move");
    } 
    public void secondMOveChoice(){
        System.out.println("Second Move");
    }
    public void thirdMoveChoice(){
        System.out.println("Third Move");
    }

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
        Test test = new Test();
        Method[] method = test.getClass().getMethods();
        //firstMoveChoice
        method[0].invoke(test, null);
        //secondMoveChoice
        method[1].invoke(test, null);
        //thirdMoveChoice
        method[2].invoke(test, null);
    }

}

Reflection è un'API che viene utilizzata per esaminare o modificare il comportamento di metodi, classi, interfacce in fase di esecuzione.

  1. Le classi richieste per la riflessione sono fornite nel java.lang.reflect package .
  2. Reflection ci fornisce informazioni sulla classe a cui appartiene un oggetto e anche i metodi di quella classe che possono essere eseguiti usando l'oggetto.
  3. Attraverso la riflessione possiamo invocare i metodi in fase di esecuzione indipendentemente dallo specifico identificatore di accesso utilizzato con essi.

I pacchetti java.lang e java.lang.reflect forniscono classi per la riflessione java.

La riflessione può essere utilizzata per ottenere informazioni su -

  1. Classe Il metodo getClass() viene utilizzato per ottenere il nome della classe a cui appartiene un oggetto.

  2. Costruttori Il metodo getConstructors() viene utilizzato per ottenere i costruttori pubblici della classe a cui appartiene un oggetto.

  3. Metodi Il metodo getMethods() viene utilizzato per ottenere i metodi pubblici della classe a cui appartiene un oggetto.

L' API Reflection è utilizzata principalmente in:

IDE (Integrated Development Environment) ad es. Eclipse, MyEclipse, NetBeans ecc.
Debugger e strumenti di test ecc.

Vantaggi dell'utilizzo della riflessione:

Funzionalità di estensibilità: un'applicazione può utilizzare classi esterne definite dall'utente creando istanze di oggetti di estensibilità utilizzando i loro nomi completi.

Strumenti di debug e test: i debugger utilizzano la proprietà di reflection per esaminare membri privati ​​sulle classi.

svantaggi:

Sovraccarico delle prestazioni: le operazioni riflettenti hanno prestazioni più lente rispetto alle controparti non riflettenti e dovrebbero essere evitate in sezioni di codice chiamate frequentemente in applicazioni sensibili alle prestazioni.

Esposizione di interni: il codice riflettente rompe le astrazioni e quindi può modificare il comportamento con gli aggiornamenti della piattaforma.

Rif: Java Reflection javarevisited.blogspot.in


Usi di riflessione

Reflection viene comunemente utilizzato dai programmi che richiedono la possibilità di esaminare o modificare il comportamento di runtime delle applicazioni in esecuzione nella Java virtual machine. Questa è una funzionalità relativamente avanzata e dovrebbe essere utilizzata solo da sviluppatori che hanno una conoscenza approfondita dei fondamenti della lingua. Con questo avvertimento in mente, la riflessione è una tecnica potente e può consentire alle applicazioni di eseguire operazioni che altrimenti sarebbero impossibili.

Funzionalità di estensibilità

Un'applicazione può fare uso di classi esterne definite dall'utente creando istanze di oggetti di estensibilità usando i loro nomi completi. Browser di classe e ambienti di sviluppo visivo Un browser di classe deve essere in grado di enumerare i membri delle classi. Gli ambienti di sviluppo visuale possono trarre vantaggio dall'utilizzo delle informazioni sul tipo disponibili in reflection per aiutare lo sviluppatore nella scrittura del codice corretto. Debugger e strumenti di test I debugger devono essere in grado di esaminare i membri privati ​​nelle classi. I cablaggi di prova possono utilizzare la riflessione per chiamare in modo sistematico un set di API individuabili definito in una classe, per garantire un livello elevato di copertura del codice in una suite di test.

Inconvenienti di riflessione

La riflessione è potente, ma non dovrebbe essere usata indiscriminatamente. Se è possibile eseguire un'operazione senza utilizzare la riflessione, è preferibile evitare di utilizzarla. Le seguenti preoccupazioni dovrebbero essere tenute a mente quando si accede al codice tramite riflessione.

  • Sovraccarico delle prestazioni

Poiché la riflessione riguarda tipi risolti dinamicamente, non è possibile eseguire determinate ottimizzazioni della macchina virtuale Java. Di conseguenza, le operazioni di riflessione hanno prestazioni più lente rispetto alle controparti non riflettenti e dovrebbero essere evitate in sezioni di codice chiamate frequentemente in applicazioni sensibili alle prestazioni.

  • Restrizioni di sicurezza

Reflection richiede un'autorizzazione di runtime che potrebbe non essere presente durante l'esecuzione in un gestore della sicurezza. Questa è una considerazione importante per il codice che deve essere eseguito in un contesto di sicurezza limitato, come in un'applet.

  • Esposizione di interni

Poiché la riflessione consente al codice di eseguire operazioni che sarebbero illegali in codice non riflettente, come l'accesso a campi e metodi privati, l'uso della riflessione può provocare effetti collaterali imprevisti, che possono rendere il codice non funzionale e distruggere la portabilità. Il codice riflettente rompe le astrazioni e quindi può modificare il comportamento con gli aggiornamenti della piattaforma.

fonte: l'API di Reflection





terminology