제이온

[Java] Concetto e utilizzo della Reflection

Creato: 2024-04-25

Creato: 2024-04-25 22:27

Cos'è la Reflection?

La Reflection è un'API che supporta la creazione di istanze di una classe desiderata attraverso l'oggetto di tipo Class caricato nell'area heap e supporta l'accesso ai campi e ai metodi dell'istanza indipendentemente dai modificatori di accesso.



Qui, la classe caricata significa che dopo che il Class Loader della JVM ha completato il caricamento del file di classe, viene creato un oggetto di tipo Classche contiene le informazioni di quella classe e viene memorizzato nell'area heap della memoria. Si noti che è diverso dall'oggetto creato con la parola chiave new. Se non si capisce bene l'oggetto di tipo Class, è consigliabile consultare la documentazione JDK dell'oggetto java.lang.class.


Come si usa

Prima di utilizzare la Reflection, è necessario ottenere l'oggetto di tipo Class caricato nell'area heap. Esistono tre metodi.


  • Ottenere tramite Classe.class
  • Ottenere tramite Istanza.getClass()
  • Ottenere tramite Class.forName("NomeClasse")


È possibile verificare che le istanze di tipo Class ottenute con i tre metodi siano tutte uguali. Poiché il valore hash è lo stesso indipendentemente dal metodo utilizzato, è possibile utilizzarlo in modo appropriato a seconda della situazione.


Ora, tramite l'oggetto di tipo Class ottenuto, è possibile creare un'istanza di quella classe e accedere ai campi e ai metodi dell'istanza indipendentemente dai modificatori di accesso. Innanzitutto, creiamo un'istanza di quella classe.


È possibile ottenere il costruttore tramite getConstructor() e creare dinamicamente un'istanza di Member tramite newInstance().

Infine, accediamo e utilizziamo i campi e i metodi dell'istanza indipendentemente dai modificatori di accesso.

È possibile ottenere tutte le variabili di istanza della classe tramite getDeclaredFileds() e ottenere il valore del campo tramite get() e modificare il valore del campo tramite set(). In questo caso, si noti che quando si accede a un campo con un modificatore di accesso private, è necessario impostare l'argomento di setAccessible() su true.


Allo stesso modo, è possibile ottenere il metodo tramite getDeclaredMethod(). In questo caso, è necessario passare come argomenti il nome del metodo e il tipo di parametro. Allo stesso modo, quando si accede a un metodo con un modificatore di accesso private, è necessario impostare l'argomento di setAccessible() su true. Infine, è possibile chiamare il metodo ottenuto tramite l'API Reflection tramite il metodo invoke().


Vantaggi e svantaggi

  • Vantaggi
    • Ha la flessibilità di eseguire operazioni necessarie accedendo ai campi e ai metodi indipendentemente dai modificatori di accesso creando istanze di classi in fase di esecuzione.
  • Svantaggi
    • Compromissione dell'incapsulamento.
    • Poiché le istanze vengono create in fase di esecuzione, il tipo non può essere controllato in fase di compilazione.
    • Poiché le istanze vengono create in fase di esecuzione, è difficile capire il flusso di esecuzione specifico.
    • Le prestazioni sono più lente rispetto all'accesso ai campi e ai metodi utilizzando semplicemente i metodi. (Non è sempre lento.)


Motivo dell'utilizzo

Tramite l'API Reflection, è possibile accedere alle informazioni sulla classe in fase di esecuzione e manipolare la classe come si desidera. È persino possibile manipolare i campi e i metodi dichiarati con il modificatore di accesso private. Poiché ciò viola l'incapsulamento, che è importante nella progettazione orientata agli oggetti, potrebbe sembrare una tecnologia da non utilizzare.


Nello sviluppo di console di piccole dimensioni, lo sviluppatore può comprendere completamente gli oggetti e le relazioni di dipendenza che saranno utilizzati nel programma in fase di compilazione. Tuttavia, nello sviluppo su larga scala come i framework, è difficile comprendere i numerosi oggetti e le relazioni di dipendenza. In questo caso, utilizzando la Reflection, è possibile creare dinamicamente classi e stabilire relazioni di dipendenza.


Ad esempio, osservando Bean Factory di Spring, si può notare che se si applica solo l'annotazione @Controller, @Service o @Repository, Bean Factory crea e gestisce automaticamente la classe a cui è applicata l'annotazione. Lo sviluppatore non ha mai comunicato a Bean Factory la classe in questione, ma ciò è possibile grazie alla Reflection. In fase di esecuzione, se viene trovata una classe a cui è applicata l'annotazione, viene creata un'istanza della classe tramite Reflection, vengono iniettati i campi necessari e viene memorizzata in Bean Factory.


Naturalmente, come detto sopra, poiché viola l'incapsulamento, è meglio utilizzarlo solo quando necessario.


Fonti

Commenti0