Modifiche alle API di base

« Older   Newer »
 
  Share  
.
  1. Jullian
        Like  
     
    .

    User deleted


    Modifiche alle API di base



    StringBuilder

    Nello sviluppo in Java si ha sempre a che fare con tipi di base matematici, logici e catene di testo. Sappiamo bene che in java la classe che si occupa di rappresentare un testo è la classe String (package java.lang) e probabilmente l'abbiamo utilizzata una miriade di volte senza porci troppi problemi alle performance derivanti dal suo uso.

    La prima cosa da sottolineare è che l'oggetto String è un oggetto immutabile, cioè, una volta creato, non può essere modificato. Di fatto, nel momento in cui modifichiamo un oggetto String, in Java, ne stiamo creando un'altra istanza, rimpiazzando quella precedente. Gli stessi operatori di append (x+="aaa") non fanno altro che fare l'override dei metodi presenti nella classe StringBuffer con la quale la classe String viene gestita per questioni di performance.

    Proprio per questo motivo in ambiente pre java 1.5 il modo più ovvio per gestire catene di testo mutabili era quello di usare direttamente la classe StringBuffer ed i relativi metodi per la gestione del testo (in particolare del metodo append e dei metodi replace). La classe è una threadsafe, il che consente di poter effettuare le operazioni sull'oggetto StringBuffer condividendolo tra diversi thread.

    StringBuilder è identica a StringBuffer, stessi metodi stessa logica, unica differenza: non è threadsafe. Le performance migliorano in maniera netta, in particolare considerando che molti programmi fanno un notevole uso delle stringhe e della loro modifica durante il ciclo di vita del software. L'utilizzo, quindi, d'ora in poi dovrebbe essere scontato a favore della nuova classe introdotta, nel momento in cui non abbiamo da gestire aspetti legati all'accesso concorrente alla risorsa.

    In ambiente enterprise ciò risulta sempre, quindi è evidente che in questo caso utilizzeremo sempre oggetti StringBuilder per la gestione di stringhe. Abbiamo misurato le prestazioni delle tre classi con un semplice esempio che potete effettuare voi stessi:

    Listato 13.1. Test sull'uso delle Stringhe
    package it.html.tiger;

    public class StringComparison {
    /**
    * @param args
    */
    public static void main(String[] args) {
    long start=System.currentTimeMillis();
    testString();
    long end=System.currentTimeMillis();
    System.out.println("Tempo di esecuzione testString() "+(end-start)+" millis.");

    start=System.currentTimeMillis();
    testStringBuffer();
    end=System.currentTimeMillis();
    System.out.println("Tempo di esecuzione testStringBuffer() "+(end-start)+" millis.");

    start=System.currentTimeMillis();
    testStringBuilder();
    end=System.currentTimeMillis();
    System.out.println("Tempo di esecuzione testStringBuilder() "+(end-start)+" millis.");
    }

    private static void testString() {
    String x = "";
    for(int i=0;i<15000;i++){
    //operazione di append
    x+=i;
    }
    }

    private static void testStringBuffer() {
    StringBuffer x = new StringBuffer("");
    for(int i=0;i<15000;i++){
    //operazione di append
    x.append(i);
    }
    }

    private static void testStringBuilder() {
    StringBuilder x = new StringBuilder("");
    for(int i=0;i<15000;i++){
    //operazione di append
    x.append(i);
    }
    }
    }
    Ecco il risultato ottenuto:

    Tempo di esecuzione testString() 1656 millis.
    Tempo di esecuzione testStringBuffer() 16 millis.
    Tempo di esecuzione testStringBuilder() 0 millis.

    Formatter, formattazione del testo


    Uno dei problemi che spesso gli sviluppatori hanno è quello relativo alla gestione della formattazione del testo. Infatti, come sappiamo, la rappresentazione può differire in base alle diverse esigenze che possiamo avere nello sviluppo di un programma.

    Seppure banali e ripetitive, queste situazioni, quando si manifestano, mettono a dura prova il miglior programmatore. Altro problema è legato al fatto che, non utilizzando una modalità standard, siamo costretti ogni volta a reinventare la stessa soluzione da zero.

    java.util.Format è l'implementazione base che si incarica di gestire gli aspetti di conversione e rappresentazione, anche se spesso vedremo che non la utilizzeremo direttamente.

    Listato 14.1. Primi esempi di formattazione del testo
    import java.util.Date;
    import java.util.Formatter;

    public class FormatterTest {

    public static void main(String[] args) {
    String name = "Pasquale";
    Date today = new Date();
    double cifra=12.332334;

    //Creiamo un oggetto formatter
    Formatter formatter = new Formatter ();
    formatter.format("Buongiorno %­s, sono le %­tT", name, today);
    System.out.println(formatter);
    Possiamo creare una nuova istanza della classe e, attraverso il metodo format, effettuare la formattazione desiderata. Il metodo format() si aspetta una stringa e zero o n Objects (in modo da poter formattare un numero indefinito di parametri).

    La notazione da usare è un segno di percentuale seguito da una serie di caratteri con cui diciamo al metodo come formattare. In questo caso stiamo formattando una stringa (%­s) e una data (%­T). La sintassi è piuttosto vasta ed è perfettamente spiegata nella documentazione delle API della classe. Proseguiamo con l'esempio:

    //Usiamo in metodo format
    System.out.format("Buongiorno %­s, sono le %­tT", name, today);

    //Usiamo il metodo printf sullo stream out
    System.out.printf("\nBuongiorno %­s, sono le %­tT", name, today);

    //Formattiamo una cifra
    System.out.printf("\nCiao %­s, stampo la cifra %.2f con 2 cifre decimali", name, cifra );

    //Possibilità di definire l'ordine dei parametri e di stamparli n volte
    System.out.printf("\nCiao %2$2s, stampo la cifra %1$2.2f con 2 cifre decimali." +
    " Adios %2$2s", cifra, name );
    }
    }
    Come dicevamo precedentemente possiamo utilizzare diversi modi per scrivere la rappresentazione su un flusso di output. Infatti utilizziamo gli stessi parametri sul metodo format() di System.out. Questo perché all'interno verrà usata la classe Format.

    Nell'esempio vediamo come sia possibile utilizzare il metodo printf() sulla variabile System.out. Gli esempi ci mostrano poi come poter formattare un decimale, troncando le cifre dopo la seconda e infine come sia possibile ordinare e utilizzare i parametri nella rappresentazione testuale.

    Fino alla versione 1.4 di Java, a partire dall'oggetto System.in (InputStream), dovevamo costruirci la nostra rappresentazione utilizzando dei filtri (InputStreamReader, BufferedReader, ...) ed effettuando gli opportuni controlli.

    Java 1.5 presenta un'utilissima classe che già porta con sé tutti i metodi per la lettura e la conversione dei tipi (numerici o stringhe): java.util.Scanner.

    Questa classe presenta una lunga serie di metodi, attraverso i quali possiamo gestire un input testuale in maniera ottimale senza preoccuparci delle tipiche operazioni di conversione (ad esempio facendo controlli sui tipi). Inoltre, utilizzando le Regular Expression, è possibile già definire il comportamento, quindi ad esempio stabilire delimitatori di testo in modo da recuperare solo quello di cui abbiamo bisogno.

    L'esempio sotto è un programmino che chiede all'utente di digitare il nome del file da visualizzare e dopo legge il file mostrandolo all'utente.

    Listato 14.2. Esempio di lettura di un parametro e di un file
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.util.Scanner;

    public class TestScanner {
    public static void main(String[] args) throws FileNotFoundException {
    System.out.println("Insert file name>>");
    Scanner scan=new Scanner(System.in);
    String fileName=scan.next();
    System.out.println("Reading "+fileName);
    printToScreen(fileName);
    }
    Nel main effettuiamo la prima richiesta creando un oggetto Scanner costruito con l'InputStream di default (la console). Ovviamente qui sarà possabile montare tutti i filtri immaginabili (per bufferizzare, cifrare, ...). Segue la richiesta con il metodo next() che legge un insieme di caratteri (inseriti dall'utente) e ne restituisce una stringa, dopodiché chiamiamo la routine printToScreen(...) passando proprio tale valore.

    Prima di proseguire diciamo che è molto interessante l'insieme di metodi esposto dalla classe Scanner. è quello più generico, ma esistono i metodi nextInt(), nextDouble() che si occupano di convertire il valore passato dall'utente in tipo numerico. Questi metodi vanno di pari passo con il rispettivo metodo di controllo hasNext() che restituisce un boolean dicendoci se esiste o meno il prossimo token (quindi avremo anche hasNextInt(), hasNextDouble(), ecc).

    Bisogna utilizzare sempre i metodi nextXXX() in coppia con hasNextXXX() perché la conversione può facilmente causare eccezioni a runtime in base al valore che la classe cerca di convertire.

    Seguiamo e vediamo come si presenta il metodo utilizzato per leggere il file (e stamparne il contenuto):

    private static void printToScreen(String fileName) throws FileNotFoundException {
    Scanner scan=new Scanner(new File(fileName));

    while(scan.hasNext()){
    String tmp=scan.next();
    System.out.println(tmp);
    }
    }
    }
    All'interno del metodo creiamo un nuovo Scanner passando al costruttore un file. Effettuiamo poi un'iterazione e stampiamo il contenuto di ogni token. Abbiamo visto che uno Scanner presenta una facile interfaccia per interrogare uno stream di input. Vediamo ora un interessante metodo per effettuare la lettura di una pagina Web in maniera identica alla lettura di un file:

    Listato 14.3. Lettura di una pagina Web
    private static void printURL() throws Exception {
    URL url = new URL ("http://www.html.it/");

    Scanner scan=new Scanner(url.openConnection().getInputStream());
    scan.useDelimiter("\\Z");

    while(scan.hasNext()){
    String tmp = scan.next();
    System.out.println(tmp);
    }
    }
    In questo caso dobbiamo definire il delimitatore di fine documento (\Z), oppure avremmo dovuto bufferizzare, poiché, altrimenti, l'implementazione recupera solo i primi 1024 byte nella lettura dello stream di rete. Per il resto tutto rimane identico (e abbastanza semplice).

    Con la versione 1.6 di Java arriva un oggetto che finalmente virtualizza in tutto e per tutto una console testuale, la classe java.io.Console, appunto. Di fatto è una classe che può essere di utiità solo in applicazioni standalone e solo in virtual machine che hanno una console testuale. Il tipico modo di recuperare quest'oggetto è il metodo System.console() ed è implementato solo in versioni della virtual machine che presentano una console di testo (e solo dalla shell di comando).

    La classe è davvero interessante in quanto non dobbiamo preoccuparci di complicati gestori, di eccezioni, stream e quant'altro... molto utile per chi inizia a programmare. Inoltre c'è un metodo per chiedere la password che evita di scrivere l'echo di quello che stiamo digitando. Vediamo l'API:

    public final class Console implements Flushable {
    public PrintWriter writer() ;
    public Reader reader();

    public Console format(String fmt, Object...args);
    public Console printf(String format, Object...args);

    public String readLine(String fmt, Object...args);
    public String readLine();

    public char[] readPassword(String fmt, Object...args);
    public char[] readPassword();

    public void flush();
    }
    Il metodo più importante è senza dubbio readLine() la cui chiamata è bloccante in attesa dell'input dell'utente. Il risultato sarà una stringa. I metodi printf() e format() effettuano una stampa sull'output della console, mentre readPassword() restituisce un array che rappresenta i caratteri di input dell'utente. Questo metodo, come dicevamo, è stato codificato per evitare di mostrare il testo digitato (come in qualsiasi applicazione che chiede una password).

    Vediamo un esempio concreto dove utilizziamo solo l'interfaccia Console per tutte le operazioni di input/output attraverso i metodi appena visti.

    Listato 14.4. Esempio di utilizzo dell'interfaccia Console
    package it.html.j16;
    import java.io.Console;

    public class ConsoleTest {
    public static void main(String[] args) {
    //Recuperiamo l'istanza di Console
    //associata a questa macchina virtuale
    Console console = System.console();

    //Utilizziamola per scrivere in output
    console.printf("Benvenuto alla console Java 1.6");

    if (args.length>0){
    //Ora chiediamo un valore in input (notare il formato %­s)
    String line = console.readLine("\nPrego, %­s, inserisci un testo >>", args[0]);

    //facciamo l'eco uppercase
    console.printf("Echo: "+line.toUpperCase());

    char pwd[] = console.readPassword("\nPrego, %­s, inserisci il PIN >>", args[0]);

    if (pinEsatto(pwd))
    console.printf("Bene! PIN CORRETTO!");
    else
    //lo mostriamo giusto per vedere la rappresentazione
    //altrimenti non avrebbe senso
    console.printf("PIN ERRATO!");
    }else{
    //Mostro la sintassi
    console.printf("\nPrego inserire un argomento: java it.html.j16.ConsoleTest yourName");
    }
    }

    private static boolean pinEsatto(char[] pwd) {
    char pinEsatto[] = {'H','T','M','L','.','I','T'};
    //Usiamo l'utility della classe Arrays
    return java.util.Arrays.equals(pwd, pinEsatto);
    }
    }
    All'utente chiediamo due operazioni di scrittura, una richiesta di una stringa normale, giusto per effettuare una banale operazione di echo, ed una password. Sulla password effettuiamo un controllo e nel caso di pin positivo lo notifichiamo positivamente. Fate attenzione perché il codice qui non funzionerà se non eseguito da una shell di comando. Eseguire questa classe dal pannello di Eclipse, per esempio, darà un valore null alla chiamata System.console().

    Array, Queue e typed collections


    A partire dalla versione Java 5 c'è l'introduzione di una serie nuova di realizzazioni concrete di Collection e la modifica alla gerarchia delle collezioni con l'aggiunta del tipo Queue. Il tipo Queue (da non confondersi con le Queue di JMS) era una di quelle strutture dati mancanti nella gerarchia delle collezioni, spesso utilizzata per la gestione delle politiche FIFO (First In First Out). Ora, grazie alla sua introduzione, la gerarchia si presenta così:

    Figura 15.1. Gerarchia


    Queue è un nuovo tipo che eredita direttamente da Collection e presenta diverse implementazioni pratiche. Ai fini della logica della struttura dati i metodi offer() e poll() sono quelli fondamentali per l'inserimento e la rimozione di elementi secondo la logica FIFO.

    Listato 15.1. Una classe di prova per effettuare test
    package it.html.java5;

    import java.util.LinkedList;
    import java.util.PriorityQueue;
    import java.util.Queue;

    public class QueueTest {

    public static void main(String[] args) {
    System.out.println("Ordinamento classico, secondo l'ordine d'arrivo");
    Queue<string> queue= new LinkedList<string>();

    for (int i=0; i<50; i++){
    queue.offer("String #"+i);
    }

    while(!queue.isEmpty()){
    System.out.println(queue.poll());
    }
    //..
    Nel primo caso ci troviamo di fronte ad una situazione classica, una coda tipica, ordinata per ordine di arrivo (quindi FIFO). La coppia di metodi offer()-poll() ci garantisce la consistenza della coda e del suo ordine. Eseguendo il codice ci aspettiamo di vedere le stringhe ordinate per identificativo crescente. Si noti che il tipo concreto è LinkedList che è stato reimplementato per garantire l'estensione dell'interfaccia Queue.

    Listato 15.2. Esempio di utilizzo di PriorityQueue
    //..
    System.out.println("Ordinamento alfabetico, in base al compareTo()");
    Queue<string> queuePrio= new PriorityQueue<string>();

    for (int i=0; i<50; i++){
    queuePrio.offer("String #"+i);
    }

    while(!queuePrio.isEmpty()){
    System.out.println(queuePrio.poll());
    }
    }
    }
    La coda a priorità esegue l'estrazione degli elementi secondo la priorità assegnata. Qui lasciamo il comparatore di default (ma PriorityQueue può accettare un Comparator<e,T>) in quanto lasciamo al metodo compareTo() dell'interfaccia Comparable il compito di effettuare la comparazione. L'esecuzione in questo caso darà la lista in ordine alfabetico:

    String #0
    String #1
    String #10
    String #11
    String #12
    String #13
    String #14
    String #15
    String #16
    String #17
    String #18
    String #19
    String #2
    String #20
    String #21
    String #22
    La novità più importante è l'introduzione nella gerarchia di questo nuovo tipo. Tra le altre piccole novità introdotte sicuramente dobbiamo citare l'estensione della classe di utilità java.util.Arrays che presenta una serie di utilissimi metodi statici per la gestione di array mono e multidimensionali.

    Nuove interfacce (package java.util):

    Deque;
    BlockingDeque;
    NavigationSet;
    NavigationMap;
    ConcurrentNavigableMap.
    Di fatto queste rappresentano definizioni di nuove strutture dati. La prima è importante ed è direttamente collegata alla coda discussa nel capitolo precedente. Una Deque, è una coda a cui è possibile accedere da entrambi gli estremi (sia in inserimento che in rimozione). In alcune situazioni può essere il modello di struttura dati che necessitiamo, quindi Sun ha provveduto con l'implementazione all'interno del framework.

    Per la gestione di sistemi multithread sarà utile l'utilizzo dell'interfaccia BlockingDeque, che estende dalla prima e che effettua l'attesa di spazio disponibile, nel caso di inserimento in coda piena, e l'attesa di un elemento inserito nel caso di coda vuota.

    I Set e Map navigabili (NavigationSet e NavigationMap) definiscono il comportamento di un set e una mappa rispettivamente, permettendo delle funzioni di navigazione e attraversamento dei nodi in maniera ordinata. La versione concorrente (ConcurrentNavigableMap) verrà utilizzata nel caso di possibile accesso concorrente.

    Ovviamente, per poter realizzare queste interfacce sono state realizzate le rispettive classi che elenchiamo:

    ArrayDeque;
    LinkedBlockingDeque;
    ConcurrentSkipListSet;
    ConcurrentSkipListMap;
    AbstractMap.SimpleEntry;
    AbstractMap.SimpleImmutableEntry;
    LinkedList;
    TreeSet;
    TreeMap.
    Partiamo dalle ultime tre, che non sono dei nuovi tipi ma sono delle reimplementazioni, fatte per essere compatibili con le nuove interfacce. LinkedList ora implementa la nuova interfaccia Deque.

    ArrayDeque invece è una nuova classe che si occupa di gestire il comportamento di una Deque in concreto. Stessa cosa dicasi per LinkedBlockingDeque, che si occupa di implementare l'interfaccia BlockingDeque. In generale il naming utilizzato già indica la tipologia di implementazione che quella classe vuole realizzare, come per tutte la gerarchia del Collection framework.

    A partire dalla versione di Java 1.6 c'è l'introduzione dei metodi Array.copyOf() e Array.copyOfRange() che consentono di superare l'utilizzo della vecchia classe di utilità System.arraycopy().

    JAXP processare un documento XML


    Una delle principali mancanze, delle vecchie versioni di Java, era quella relativa a un paradigma per l'elaborazione di una sorgente XML. Nel momento in cui intendevate effettuare una lettura o qualsiasi operazione su un file XML dovevate utilizzare uno strumento proprietario (API di terze parti) con il rischio di legarvi a vita ad una specifica implementazione.

    Una delle modifiche della versione 1.4 di Java è stata quella di introdurre, tra le sue API di base, la JAXP (Java API for XML Processing). Il principale obiettivo di questa modifica è quello di astrarre l'implementazione concreta, lasciando quindi allo sviluppatore un'interfaccia generica da utilizzare, e poi un motore di parsing da poter cambiare in maniera dinamica.

    Prima di vedere l'implementazione concreta, citiamo i due modelli di parsing che vengono proposti in JAXP: SAX (Simple API for XML) e DOM (Document Object Model).

    Non entriamo nel dettaglio delle due tipologie, richiederebbe un capitolo a parte, ma per comprendere quello che segue è bene sapere che il primo è un modello di accesso semplice, basato sugli eventi incontrati nella lettura di un file XML (apertura e chiusura dei tag, attributi, ecc), il secondo è basato su una scansione del documento e di una rappresentazione dell'albero degli oggetti.

    Il primo non mantiene in memoria una rappresentazione del documento, quindi può essere utilizzato per grossi file XML o per accessi veloci. Il secondo, invece, mantiene una struttura dei nodi, quindi può essere utilizzato per documenti di dimensione ridotta o per modificare la struttura dell'albero, aggiungendo e rimuovendo dinamicamente i nodi.

    Visto che sono due possibili modelli di utilizzo, JAXP lascia la possibilità di scegliere. La libreria infatti è così composta:

    javax.xml.parsers
    org.w3c.dom
    org.xml.sax
    javax.xml.transform
    Il primo è un package generico che definisce le classi factory per poter accedere alle implementazioni concrete di SAX e DOM, e quindi poter processare i file XML.

    Il secondo definisce le classi e l'interfaccia programmatica da utilizzare nel caso di un processing DOM delle risorse XML. Qui è contenuta la definizione di Node, Attribute e in generale del modello che rappresenta l'albero dei nodi e come poterlo accedere e modificare.

    Il terzo è più semplice in quanto espone il modello programmatico SAX per processare le risorse XML, in questo caso guidato dagli eventi (quindi dalla classe Handler e relativi metodi startTag(), endTag(), ecc).

    L'ultimo package introduce la possibilità di trasformare il codice XML attraverso il meccanismo della trasformazione XSL, dando accesso a una serie di interfacce di utilità per raggiungere lo scopo.

    Come si vede dal codide, non c'è la necessità di importare librerie di terze parti ed è immediato manipolare il documento modificandone la struttura.

    Listato 16.1. Esempio di accesso DOM a un documento
    package it.html.xml;

    public class MainXML {
    public static void main(String[] args) throws Exception {
    //Recupero concretamente l'engine di parsing DOM (di default)
    DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder domparser = dbfactory.newDocumentBuilder();

    //Effettuiamo il parsing di un file
    Document doc = domparser.parse(new File("data.xml"));
    //Recuperiamo il primo nodo
    Node x = doc.getFirstChild();
    //Recupero il primo nodo TEAM del documento
    Node y = doc.getElementsByTagName("TEAM").item(0);
    //Aggiungo il nodo y a x
    x.appendChild(y);

    //Creiamo un nuovo documento
    Document doc2 = domparser.newDocument();
    //e appendiamo la rappresentazione del primo doc
    doc2.appendChild(x);

    //infine salviamo il file
    XMLSerializer serializer = new XMLSerializer();
    serializer.setOutputCharStream(new java.io.FileWriter("data2.xml"));
    serializer.serialize(doc2);
    }
    }
    L'uniformità garantita dall'interfaccia JAXP ci permette di vedere un documento DOM sempre allo stesso modo. Ciò significa che questo codice potrà essere riutilizzato anche quando cambia l'implementazione del motore di parsing sottostante. Infatti, le prime due righe di codice sono quelle che concretamente recuperano l'implementazione che poi ci garantisce un corretto utilizzo della risorsa.

    Abbiamo mostrato come funziona il DOM, ma altrettanta semplicità avrete utilizzando l'interfaccia SAX o la trasformazione XSL.


    Reflection

    L'introduzione dei tipi Generics ha portato all'inevitabile cambiamento di diverse classi oltre al framework Collection. In questo capitolo ci occupiamo di descrivere le modifiche apportate al package java.lang.reflection. Come sappiamo, la reflection è uno strumento molto potente utilizzato per analizzare e modificare a runtime il comportamento del linguaggio tramite introspezione. L'introduzione dei tipi generici porta quindi al cambiamento di molte interfacce e classi del package attraverso il loro utilizzo.

    Anche l'introduzione delle annotazioni porta all'evoluzione del package con l'introduzione di metodi per accedere a runtime alla definizione delle annotazioni. Ad esempio, la classe java.lang.reflection.Class introduce i due metodi:

    <a extends Annotation> A getAnnotation(Class<a> annotationClass)
    Annotation[] getAnnotations()
    Attraverso questi metodi riusciamo a recuperare a runtime il tipo Annotation che dinamicamente possiamo interrogare per gestire il comportamento dinamico definito dall'annotazione.

    Non vediamo tutte le modifiche del package perché sono tante ed applicate a tutte le classi, ci limitiamo a fare un riassunto dei principali tipi di modifica in modo da avere una panoramica generale (per consultare le modifiche basta accedere a Javadocs API).

    Supporto ai tipi generics: tutte le principali classi vengono riviste aggiungendo i tipi generics, laddove possibile, per poter sfruttare questo nuovo paradigma.

    Ad esempio, adesso dovremo utilizzare la seguente dichiarazione:

    Class<unaclasse> x,y,z;
    //..
    Constructor<miaclasse> constr = getDeclaredConstructor(x,y,z)
    Supporto per le annotazioni: anche qui abbiamo anticipato l'introduzione dei metodi per poter accedere dinamicamente alle annotazioni.

    Supporto per i tipi enum: anche l'introduzione del tipo enum, apporta modifiche al package per far si di effettuare introspezione dinamica.

    Supporto per var args: la possibilità di effettuare di gestire un numero di argomenti variabili necessita una struttura opportuna per la sua gestione.

    Metodi di utilità: sono presenti una serie di nuovi metodi di utilità per poter utilizzare al meglio la reflection.

    La classe java.lang.reflect.Class è stata resa generica, quindi ora dovremo utilizzarla come segue:

    Class<miaclasse> c;

     
    .
0 replies since 17/5/2010, 10:13   16 views
  Share  
.