|
Identificazione del tipo a run-time
Pagina :
1 |
2
| 3
| 4
Può essere utile, in fase di esecuzione (run-time)
conoscere il tipo di un oggetto. Si pensi ad esempio alla gestione
di più oggetti memorizzati in una Collection "archivio" contenente i
seguenti tipi:
Foto ( legato ad un file di immagine);
Audio ( legato ad un file audio);
Documento ( legato ad un file di testo);
Memo ( Una Stringa legata ad una data );
Sarebbe possibile effettuare un'interrogazione per poter
identificare ciascun tipo ospitato nella collection e quindi
richiamare gli opportuni metodi relativi al tipo identificato.
Ricordando inoltre che laddove si utilizzi un oggetto di tipo
Collection si devono ridefinire i metodi hashcode ed equals, quest'ultimo
metodo potrebbe essere implementato basandosi sulla conoscenza del
tipo degli oggetti da confrontare (si veda l'articolo "Collection:
ridefinizione dei metodi equals e hashcode" ).
Mentre un'applicazione è in esecuzione, il sistema run-time di java
identifica il tipo di ciascun oggetto in esecuzione registrandone la
classe di appartenenza. Questo processo si chiama appunto
identificazione del tipo a run-time. Tuttavia esiste una classe
appartenente all' API java.lang, che permette di accedere a questa
informazione a livello di compilazione, ossia la rende gestibile dal
programmatore. La classe in questione si chiama java.lang.Class. Si
può dire quindi che un oggetto Class è la rappresentazione di un
qualsiasi Tipo (Classe) Java. Ogni oggetto Java eredita dalla classe
java.lang.Object il metodo getClass( ),che restituisce, appunto, un'
istanza di tipo Class .
GenericoOggetto g; Class cl = g.getClass();
Un'altro metodo per ottenere un oggetto di tipo class è il seguente:
Class c = MioTipo.class; Class c2 = int.class;
che ancora vale per qualsiasi tipo Java. Abbiamo così a disposizione
un metodo per "registrare" un qualsiasi Tipo in un oggetto Class.
Vediamo adesso quali utili informazioni Class è capace di fornire.
Class dispone del metodo getName(), capace di restituire una stringa
contenente il nome della classe registrata e quindi utilizzabile dal
programmatore. Ad esempio:
System.out.println( g.getClass().getName() )
stampa:
GenericoOggetto
Si ha quindi la possibilità di realizzare programmi capaci di
adattarsi a run-time così come previsto dal programmatore, in quanto
un oggetto Class garantisce al programmatore un riferimento concreto
intorno al quale modellare il flusso di controllo di un processo. Ad
esempio, per la gestione della collection Agenda si potrebbe
utilizzare getName() come segue:
String nomeClasse; ... public void
inserisci(Object obj){ nomeClasse = obj.getClass().getName(); if (
nomeClasse.equals("Foto")) { … gestisciFoto(obj); … } else If(
nomeClasse.equals("Audio")) { …; gestisciAudio(obj); … } else If(
nomeClasse.equals("Documento")) { …; gestisciDocumento(obj); …; }
else { rifiutaTipo( nomeClasse ); } }; ...
Un altro metodo fornito da Class è forName( String className )
E' un metodo statico che restituisce un oggetto Class contenente il
tipo identificato dalla stringa className.Vediamone un esempio:
String className = "Foto"; Class cl = Class.forName( className );
Ovviamente, nel caso in cui la classe non esistesse si genererebbe
un'eccezione, quindi il tutto deve essere racchiuso in un blocco
try-catch come segue :
try{ String className = "Foto"; Class cl = Class.forName(
className ); }catch(ClassNotFoundException cnfe){ …; }
Dopo questo primo approccio possiamo passare ad una descrizione più
sistematica delle problematiche:
? Object getNewInstance(); Restituisce un'istanza del Tipo
registrato nell'oggetto Class. Questo metodo funziona solo se il
costruttore della classe da istanziare non prevede argomenti. Nel
caso in cui vi siano parametri da specificare si deve utilizzare il
metodo newInstance(Object[] parametri) della classe
java.lang.reflect.Construct ( si veda l'articolo dedicato alla
Riflessione ). Tale metodo lancia le seguenti eccezioni di tipo
checked (ossia da catturare necessariamente ): 1.
IllegalAccessException; 2. InstantiationException;
? static Class forName( String nomeClasse ); Restituisce un oggetto
Class contenente il Tipo specificato da nomeClasse. E' bene
ricordare che nomeClasse deve contenere il percorso completo del
Tipo rispetto al package di appartenenza ( es: "java.lang.String" e
non "String" ) Tale metodo lancia la seguente eccezione di tipo
checked: 1. ClassNotFoundException;
Questi due metodi si possono usare come segue:
try{ cl = Class.forName(nomeClasse); Object
obj = cl.newInstance(); ...; }catch(ClassNotFoundException cnfe){
...; }catch(IllegalAccessException iae){ ...; }catch(InstantiationException
ie){ ...; }
? String toString(); Restituisce il nome della classe o
dell'interfaccia. Se si tratta di una classe, la parola "class"
precede il nome della classe, altrimenti "interface" se si tratta di
un'interfaccia.
? Class[ ] getInterface(); Ritorna un array di oggetti Class
contenenti tutte le interfacce implementate dal Tipo registrato
nell'oggetto class.
Un esempio completo.
E' Costituito dal package lezioni
contenente due classi: 1. Classe RunTimeClass; 2. Classe Tester;
La classe RunTimeClass possiede 2 costruttori:
RunTimeClass(Object obj) Visualizza il nome del Tipo di
qualsiasi oggetto passatogli nel costruttore
La Classe Tester gestisce RunTimeClass creando più istanze di essa
RunTimeClass(String nomeClasse) Crea un'istanza e ne
visualizza il nome mediante Class.getName() e Object.toString.
Classe RunTimeClass. package lezioni;
public class RunTimeClass {
Class cl;
String nomeTipo;
//Visualizza il nome del tipo di qualsiasi oggetto
public RunTimeClass(Object obj) {
cl = obj.getClass();
nomeTipo = cl.getName();
System.out.println( "\ta. Metodo Class.GetName(): " + nomeTipo );
System.out.println( "\tb. Metodo Class.toString(): " + cl );
System.out.println( "\tc. Metodo toString() dell'oggetto : " + obj
);
}
/*Crea un'istanza e ne visualizza il nome mediante
Class.getName() e Object.toString */
public RunTimeClass(String nomeClasse) {
try{
cl = Class.forName(nomeClasse);
Object obj = cl.newInstance();
System.out.println(
"\t1. Nuova istanza di: " +
obj.getClass().getName()
);
System.out.println( "\t2. Metodo Class.toString(): " + cl );
System.out.println( "\t3. Nuova istanza --> toString(): " + obj );
}catch(ClassNotFoundException cnfe){
System.out.println( "\tClasse sconosciuta" );
}catch(IllegalAccessException iae){
System.out.println( "\tAccesso illegale" );
}catch(InstantiationException ie){
System.out.println( "\tErrore Istanza\n" );
}
}
}
Classe Tester. package lezioni;
public class Tester {
public String toString(){
return "Sono un oggetto Tester " ;
}
public static void main(String[] args) {
System.out.println( "\nIstanza rtc1{" );
RunTimeClass rtc1 = new RunTimeClass("java.lang.String");
System.out.println( "}\nIstanza rtc2{" );
RunTimeClass rtc2 = new RunTimeClass(new Integer(3));
System.out.println( "}\nIstanza rtc3:{" );
RunTimeClass rtc3 = new RunTimeClass("lezioni.Tester");
}
}
Visualizzera':
Istanza rc1{ 1. Nuova istanza di: java.lang.String
2. Metodo Class.toString(): class java.lang.String
3. Nuova istanza --> toString():
}
Istanza rc2{
a. Metodo Class.GetName(): java.lang.Integer
b. Metodo Class.toString(): class java.lang.Integer
c. Metodo toString() dell'oggetto : 3
} Istanza rc3:{
1. Nuova istanza di: lezioni.Tester
2. Metodo Class.toString(): class lezioni.Tester
3. Nuova istanza --> toString(): Sono un oggetto Tester
Class, inoltre, presenta dei metodi particolari che restituiscono
oggetti di tipo Field,Method,Constructor. Queste Classi si
comportano similmente a Class ma, come il loro nome lascia intuire,
si applicano non per gestire il Tipo di un oggetto, bensì,
rispettivamente, i suoi campi, metodi e costruttori ( si veda
l'articolo articolo sulla Riflessione) .Riassumiamo quindi ed
ampliamo le classi ed i metodi citati in questo articolo:
API: java.lang.Object
? Class getClass();
API: java.lang.Class
? static Class forName( String className )
? public String getName();
? public String toString();
? public Class getSuperClass();
? public Class[] getInterfaces();
? public boolean isInterfaces();
? public Object newInstance();
? public Field[] getFields();
Restituisce un array di oggetti java.reflect.Field per la gestione a
run-time dei Campi pubblici del Tipo rappresentato da un'oggetto
Class.
? public Method[] getMethods();
Restituisce un array di oggetti java.reflect.Method per la gestione
a run-time dei metodi pubblici del Tipo rappresentato da un'oggetto
Class.
? public Constructor[] getConstructors();
Restituisce un array di oggetti java.reflect.Constructor per la
gestione a run-time dei costruttori pubblici Tipo rappresentato da
un'oggetto Class.
? public Field[] getDeclaredField();
Restituisce un array di oggetti java.reflect.Field per la gestione a
run-time di tutti i Campi, pubblici, privati, ereditati etc del Tipo
rappresentato da un'oggetto Class.
? public Method[] getDeclaredMethods();
Restituisce un array di oggetti java.reflect.Method per la gestione
a run-time di tutti i Metodi, pubblici, privati, ereditati etc, del
Tipo rappresentato da un'oggetto Class .
? public Constructor[] getDeclaredConstructors();
Restituisce un array di oggetti java.reflect. Constructor per la
gestione a run-time di tutti i Costruttori del Tipo rappresentato da
un'oggetto Class.
API: java.lang.reflect.Constructor
? Object newInstance( Object[] args )
Restituisce un'istanza della classe rappresentato da un'oggetto
Class utilizzando il costruttore non di default della classe da
istanziare. Object[] args contiene tutti i parametri da passare al
costruttore da utilizzare.
Pagina :
1
|
2 |
3 |
4
|