Vai alla Home Page About me Courseware Federica Living Library Federica Federica Podstudio Virtual Campus 3D La Corte in Rete
 
Il Corso Le lezioni del Corso La Cattedra
 
Materiali di approfondimento Risorse Web Il Podcast di questa lezione

Marco Faella » 18.La riflessione


La riflessione e la classe Class

La riflessione (o introspezione) è una caratteristica di Java che permette ai programmi di investigare a tempo di esecuzione sui tipi effettivi degli oggetti manipolati.

Il cardine della riflessione è rappresentato dalla classe Class.
Ciascun oggetto di classe Class rappresenta una delle classi del programma

  • la JVM si occupa di istanziare un oggetto Class per ogni nuova classe caricata in memoria;
  • solo la JVM può istanziare la classe Class;
  • un oggetto di tipo Class contiene tutte le informazioni relative alla classe che esso rappresenta: i costruttori, i metodi, i campi, ed anche le eventuali classi interne;
  • tramite questo oggetto, è possibile conoscere a run-time le caratteristiche di una classe che non è nota al momento della compilazione.

Pur non essendo classi, anche i tipi primitivi hanno un corrispondente oggetto di tipo Class

La classe Class ha un parametro di tipo, che chiameremo “T”.
Come un serpente che, apparentemente, si morde la coda, il parametro di tipo di un oggetto Class indica il tipo che questo oggetto rappresenta. Ad esempio, se x è l’oggetto Class relativo alla classe Employee, il tipo di x è Class <Employee>.
Nelle prossime slide, vedremo come il parametro di tipo viene utilizzato dai metodi di Class.

Alcuni metodi della classe Class

Esaminiamo alcuni metodi della classe Class<T>:

public String getName()
restituisce il nome di questa classe, completo di eventuali nomi di pacchetti.

public T newInstance()
crea e restituisce un nuovo oggetto di questa classe, invocando un costruttore senza argomenti, che questa classe deve possedere.

public static Class<?> forName(String name)
restituisce l’oggetto Class corrispondente alla classe di nome “name”; la stringa “name” deve contenere anche l’indicazione degli eventuali pacchetti cui la classe appartiene.

public Class<? super T> getSuperclass()
restituisce l’oggetto Class corrispondente alla superclasse diretta di questa; se questa è Object, oppure è un’interfaccia o un tipo base, il metodo restituisce null.

public boolean isInstance(Object x)
restituisce vero se (e solo se) il tipo effettivo di x è sottotipo di questa classe.

Ottenere riferimenti agli oggetti di tipo Class

Per ottenere un riferimento ad un oggetto di tipo Class, è possibile utilizzare uno dei seguenti tre metodi.

Primo metodo:

Nella classe Object, è presente il metodo public Class < ? extends Object > getClass()

Questo metodo restituisce l’oggetto Class corrispondente al tipo effettivo di questo oggetto.
Il tipo restituito di getClass merita attenzione.
Supponiamo di applicare getClass ad un oggetto di tipo dichiarato Employee:

Employee e = ...
??? = e.getClass();

A che tipo di variabile ci aspettiamo di poter assegnare il risultato della chiamata?
A prima vista, la risposta sembrerebbe Class < Employee >
A pensarci meglio, se il tipo effettivo di “e” fosse Manager, l’oggetto restituito da getClass sarebbe di tipo Class<Manager>, che non è assegnabile a Class < Employee >!
Pertanto, il tipo più appropriato (cioè, più specifico) a cui possiamo assegnare il risultato è Class <? extends Employee >

Ottenere riferimenti agli oggetti di tipo Class

Quindi, il tipo restituito di getClass dovrebbe esprimere il seguente concetto:

applicato ad una classe A (che lo eredita da Object), questo metodo restituisce un oggetto di tipo Class < ? extends A >

Purtroppo, non è possibile esprimere in Java questo concetto di tipo restituito.
Il type-checker tratta il metodo getClass in modo particolare, simulando il tipo restituito che il linguaggio non è in grado di esprimere.
Lo strano tipo restituito ricorda al programmatore che questo metodo è soggetto ad un trattamento speciale da parte del compilatore.

Normalmente, il parametro di tipo “? extends Object” non ha senso, perché non limita in alcun modo il parametro jolly.

Ottenere riferimenti agli oggetti di tipo Class (segue)

Secondo metodo:
Il secondo metodo per ottenere un riferimento ad un oggetto di tipo Class è rappresentato dall’operatore “.class”

Tale operatore si applica al nome di una classe o di un tipo base, come in:

Employee.class
String.class
java.util.LinkedList.class
int.class

Questo operatore ha carattere statico, nel senso che il suo valore è noto al momento della compilazione.

Terzo metodo:
Il terzo metodo è rappresentato dal metodo statico forName della classe Class, che abbiamo già presentato in questa lezione.
Questa tecnica ha carattere dinamico, in quanto il valore restituito da forName non è noto al momento della compilazione.

Esercizio

Data la dichiarazione:

Employee e = new Manager(...);

Per ognuna delle seguenti espressioni, dire se è corretta o meno, e in caso affermativo calcolarne il valore

  1. e instanceof Employee
  2. e instanceof Manager
  3. e.class instanceof Employee
  4. e.getClass() == Manager
  5. e.getClass() == Employee.class
  6. e.getClass() == "Manager"
  7. e.getClass() == Manager.class
  8. e.getClass().equals(Manager.class)

Ottenere informazioni su una classe

I metodi della classe Class permettono di ricavare numerose informazioni sulla classe in questione. In particolare, è possibile conoscere l’elenco di tutti i campi, metodi e costruttori appartenenti alla classe. A tale scopo, esistono le classi Field, Method e Constructor, che rappresentano gli elementi omonimi di una classe.
Per ottenere tali informazioni, sono utili i seguenti metodi di Class:

public Field[] getFields()
public Field[] getDeclaredFields()
public Method[] getMethods()
public Method[] getDeclaredMethods()
public Constructor[] getConstructors()
public Constructor[] getDeclaredConstructors()

Il metodo getFields restituisce tutti i campi pubblici di questa classe, anche ereditati

  • getMethods è analogo a getFields
  • getConstructors restituisce semplicemente i costruttori pubblici di questa classe

Il metodo getDeclaredFields restituisce tutti i campi dichiarati in questa classe (e non nelle superclassi)

  • indipendentemente dalla loro visibilità;
  • similmente, getDeclaredMethods e getDeclaredConstructors.

La classe Field

La classe Field rappresenta un campo di una classe.
Essa dispone di metodi per leggere e modificare il contenuto di un campo, conoscere il suo nome e il suo tipo.
In particolare, abbiamo: (vedi figura).

Alcuni metodi sollevano l’eccezione verificata IllegalAccessException, quando si tenta di accedere ad un campo che non è accessibile a causa della sua visibilità.


La classe Method

La classe Method rappresenta un metodo di una classe.
Essa dispone di metodi per conoscere il nome del metodo, il numero e tipo dei parametri formali e il tipo di ritorno.
Inoltre, è possibile invocare il metodo stesso.

In particolare, abbiamo: (vedi figura).

La sintassi “Object…args” indica che invoke accetta un numero variabile di argomenti.


Metodi con numero variabile di argomenti

Dalla versione 1.5, Java prevede un meccanismo per dichiarare metodi con un numero variabile di argomenti (metodi variadici, o, in breve, varargs).
Se T è un tipo di dati, con la scrittura
f(T … x)

si indica che f accetta un numero variabile di argomenti (anche zero), tutti di tipo T.
I puntini sospensivi devono essere necessariamente tre.

Gli argomenti possono essere passati separatamente, come in f(x1, x2, x3), oppure tramite un array, come in f(new T[] {x1, x2, x3}).
All’interno del metodo f, si può accedere agli argomenti utilizzando x come un array di tipo T.

Ogni metodo può avere un solo argomento variadico, che deve essere l’ultimo della lista, come il metodo invoke della classe Method, illustrato nella slide precedente

public Object invoke(Object x, Object...args)

Esercizi

1) Implementare un metodo, chiamato reset, che prende come argomento un oggetto ed imposta a zero tutti i suoi campi interi pubblici.

2) Implementare un metodo che, dato un oggetto, parte dalla classe che rappresenta il tipo effettivo dell’oggetto e ne restituisce la superclasse più generale, escludendo Object (quindi, la penultima classe, prima di arrivare a Object).

  • Contenuti protetti da Creative Commons
  • Feed RSS
  • Condividi su FriendFeed
  • Condividi su Facebook
  • Segnala su Twitter
  • Condividi su LinkedIn
Progetto "Campus Virtuale" dell'Università degli Studi di Napoli Federico II, realizzato con il cofinanziamento dell'Unione europea. Asse V - Società dell'informazione - Obiettivo Operativo 5.1 e-Government ed e-Inclusion

Fatal error: Call to undefined function federicaDebug() in /usr/local/apache/htdocs/html/footer.php on line 93