Corso Java - Quinta lezione: array, vector e applet

Dopo aver concluso con la scorsa lezione la parte introduttiva del nostro excursus, possiamo cominciare ad occuparci di alcuni aspetti intimi del linguaggio e alla conoscenza delle classi più utili.
Corso Java - Quinta lezione: array, vector e applet

Dopo aver concluso con la scorsa lezione la parte introduttiva del nostro excursus, possiamo cominciare ad occuparci di alcuni aspetti intimi del linguaggio e alla conoscenza delle classi più utili. Cominceremo con le prime strutture dati semplici (array e vector) e con le applet.

Array e Vector
In molti dei nostri programmi abbiamo la necessità di organizzare una certa quantità di dati, omogenei e non, in maniera compatta, al fine di creare una “lista” di variabili (non importa il tipo) che siano raggruppate da un punto di vista logico. Se, ad esempio, abbiamo bisogno di gestire una lista di nominativi risulta molto scomodo dichiarare un gran numero di variabili, una per ogni persona. Abbiamo quindi bisogno di qualcosa di leggermente più complesso, che prende il nome di struttura dati. Le strutture dati più semplici sono gli array: potete pensare ad un array come una successione di celle consecutive di memoria, ognuna delle quali è destinata ad un elemento (questa definizione non è quella più rigorosa perché riguarda da vicino l’implementazione, ma è funzionale per i nostri scopi). La dichiarazione di un array in Java ha la seguente sintassi:

Tipo-dato nome_array = new Tipo-dato[NUMERO ELEMENTI];

ad esempio

int numeri_enalotto = new int[7];

La cosa più lampante in questa sintassi è che Java considera l’array come un vero e proprio oggetto, quindi la creazione deve essere eseguita con l’operatore new. Inoltre NUMERO ELEMENTI deve necessariamente essere una costante: in genere si evita la dicitura sopra proposta e si scrive

final int MAX_NUMERI = 7;
int numeri_enalotto = new int[MAX_NUMERI];

e si tende ad utilizzare MAX_NUMERI in luogo del suo valore durante tutto il programma. Il motivo è semplice: supponiamo che un giorno vengano cambiate le regole del gioco in questione (d’altro canto è già avvenuto per il totocalcio), se volete continuare ad utilizzare il programma e avete scritto numerose volte 7 invece di MAX_NUMERI dovrete fare un buon numero di modifiche. Questa operazione risulta oltremodo difficoltosa se il programma non l’avete scritto voi stessi, poiché molto spesso i commenti risultano carenti: non sarebbe quindi possibile distinguere i 7 che rappresentano la dimensione del vettore da eventuali altri 7 presenti nel programma.
Notate inoltre che fino ad ora abbiamo creato solo l’array, i singoli oggetti devono essere creati separatamente. Questi singoli elementi sono accessibili direttamente conoscendo la loro posizione nell’array che prende il nome di indice, quindi risulta conveniente accedere agli elementi del vettore tramite una variabile intera (l’indice appunto) che in questo esempio gestiamo con un ciclo for. Vogliamo inizializzare a 1 tutti gli elementi del suddetto vettore:

int i;
for ( i=0 ; i<MAX_NUMERI ; i++ )
    numeri_enalotto[i] = 1;

Quello che avete appena visto è il metodo standard per accedere a tutti gli elementi del vettore. I più attenti avranno notato che il ciclo parte da 0 (e non da uno) e termina a MAX_NUMERI -1. Non si tratta di un errore: infatti Java numeri gli elementi del vettore, come molti altri linguaggi, partendo dalla posizione zero e NON dalla posizione uno. Notate come in questo caso non abbiamo usato l’operatore new per istanziare i singoli elementi poiché si tratta di tipi di dato predefiniti: se avessimo voluto creare un array di stringhe, ad esempio, avremmo potuto inizializzarlo in questo modo:

for ( i=0 ; i<MAX_STRINGHE ; i++ )
    nomi[i] = new String("Inserire un nome");

Poiché possiamo accedere agli elementi del vettore tramite indice è del tutto valida una dicitura di questo tipo:

nomi[2] = new String("Ilsoftware.it")

nella quale dovete prestare molta attenzione al fatto che state indirizzando l’elemento in posizione due, quindi il terzo e non il secondo. A mio avviso questo è l’errore più comune commesso da chi si avvicina al linguaggio senza avere esperienze di programmazione.

Vector
Fino a qui potrebbe sembrare che poiché possiamo accedere facilmente a tutti gli elementi dell’array esso sia una struttura dati pressoché perfetta. In realtà esso ha un grosso difetto di fondo: bisogna conoscere a priori il numero massimo di dati da inserire. Se, per esempio, dobbiamo gestire un archivio destinato a crescere nel tempo è del tutto inefficiente poiché potremmo trovarci un giorno a dover correggere direttamente il codice. Al contrario nell’esempio dei numeri del super enalotto esso è sicuramente la struttura dati più conveniente poiché il numero degli elementi da considerare è noto a priori (6+1). In realtà l’array ha anche degli altri aspetti negativi relativi all’utilizzo della memoria di cui non ci occuperemo sia perché esulano dai nostri scopi sia perché nei pc moderni che dispongono di grosse quantità di memoria non siamo mai portati ad occuparcene. Al lettore basti sapere che l’array è la struttura dati indicata se il numero dei dati è conosciuto a priori (oppure è conosciuto il loro massimo valore, ad esempio nella gestione dell’anagrafica di una piccola azienda si può tranquillamente stimare un valore per eccesso) ed è relativamente basso.

Per ovviare a questo inconveniente la teoria delle strutture dati ci offre varie alternative, una delle quali è implementata in Java tramite la classe Vector che offre, rispetto all’array, i seguenti vantaggi:
– La sua dimensione può variare dinamicamente
– E’ possibile inserire e cancellare elementi in qualunque posizione senza lasciare “buchi” tramite l’invocazione di opportuni metodi
– Gli elementi del vector possono essere anche disomogenei.
La classe Vector fa parte del package java.util, quindi dobbiamo importarlo all’inizio del listato. Potete scaricare un listato che contiene esempi delle più comuni operazioni che possono essere svolte su questa struttura dati, debitamente commentati.
Per quanto riguarda l’efficienza del vector è doveroso precisare che esso è meno performante dell’array se vengono effettuate ripetute operazioni di inserimento e cancellazione e che il suo utilizzo deve essere limitato a insiemi non eccessivamente numerosi, per i quali è necessario usare strutture dati complesse o, nei casi estremi, database.

Ricerca, ordinamento ed introduzione alle applet

Ricerca e ordinamento

Una attenzione particolare deve essere data in queste pagine a due problemi classici della programmazione: la ricerca e l’ordinamento. E’ chiaro a tutti che se dobbiamo cercare un certo elemento all’interno di un insieme i cui componenti sono posti in maniera casuale l’unico modo di procedere è scandire tutti gli elementi alla ricerca dell’elemento considerato (basta un ciclo for ed un paio di if). Se invece gli elementi sono “ordinati” secondo una qualunque relazione nota a priori (ordine numerico, alfabetico ecc ecc) procediamo diversamente: nessuno si metterebbe a leggere l’intero elenco telefonico per trovare un nominativo. Per nostra fortuna nella libreria standard di Java alcune di queste operazioni sono già implementate per array di tipi di dato predefiniti. Esse sono contenute nella classe Arrays che fa parte del package java.util. In particolare è sono implementate le operazioni di inizializzazione (fill, che abbiamo anche imparato a compiere manualmente) e di ordinamento (sort). Essa inoltre implementa un algoritmo di ricerca binaria che deve essere utilizzato su array ordinati: questi metodi restituiscono l’indice del valore cercato, se presente, oppure un valore negativo. Si consideri il seguente esempio che opera su un array di interi, che supponiamo già presenti nel vettore:

final int MAX_NUMERI = 100;
int numeri = new int[MAX_NUMERI];
.....
//ordinamento del vettore
Arrays.sort(numeri);
//ricerca di un determinato valore, ad esempio 30
int key = 30;
int pos;
if((pos = Arrays.binarySearch(numeri, key)) > 0)
    System.out.println("Valore presente in posizione " +pos );
else
    System.out.println("Valore non presente");

Ci occuperemo dell’ordinamento e della ricerca di variabili che non siano tipi di dato predefinito più avanti nel corso. Per una adeguata conoscenza delle classi Vector e Arrays rimandiamo alla documentazione del linguaggio, poiché una loro trattazione esaustiva richiederebbe un intero corso indipendente. Per chi fosse interessato a questi aspetti del linguaggio consigliamo un testo di strutture dati in Java. Si tratta comunque di argomenti che richiedono un certo impegno e sono indicati solo a coloro i quali li utilizzano per lavoro o per studio.

Le applet
Presentiamo adesso, per la prima volta, uno degli argomenti più universalmente conosciuti del linguaggio Java: le applet. Si tratta di programmi Java fatti per essere inseriti in pagine web, ciò nonostante possono essere eseguiti da uno strumento chiamato appletviewer presente nella jdk. In genere, però, il bytecode (quindi non il sorgente) viene eseguito tramite un particolare interprete java integrato nei browser dell’utente finale. Il bytecode viene trasmesso all’utente direttamente insieme alla pagina web ed è per questo motivo che è necessario integrare nei browser la JVM (al momento sono integrate o disponibili JVM per tutti i browser di cui sono a conoscenza e su tutte le piattaforme). Poiché l’applet viene eseguita da un processo già in esecuzione (l’interprete) non vi è necessità di un metodo main.

Per poter visualizzare un’applet in una pagina web dovete inserire il seguente tag al suo interno:


in cui dovete sostiuire a nome_applet il nome della classe che desiderate eseguire. I valori indicati per altezza e larghezza sono dei semplici esempi.

Nello scrivere le applet ci si deve attenere ad alcune semplici regole, dettate da esigenze di programmazione e di sicurezza. La sicurezza impone, infatti, che le applet non possano fare tutto ciò che fa una comune applicazione Java, in particolare
1. non hanno accesso al file system della macchina locale, ad eccezione di alcune directory specificamente indicate dall’utente;
2. non possono in alcun modo comunicare con server diversi da quello in cui sono caricate
3. non possono avviare processi di nessun tipo sul computer locale.
4. non possono caricare programmi nativi della piattaforma locale, comprese le librerie DLL.
L’attuazione di queste norme è garantita sia da controlli sia in fase di compilazione che in esecuzione. Per quanto riguarda le esigenza di programmazione dobbiamo essenzialmente attenerci ai seguenti punti
1. la classe principale deve essere dichiarata public.
2. essa deve “ereditare” dalla classe Applet. Ci occuperemo dell’ereditarietà più avanti, per ora accettiamo il fatto che la l’applet si presenta in questo modo

import java.applet.Applet;

public class prima_applet extends Applet
{
    public void paint(Graphics page)
    {
    page.drawString("Prima applet per ilsoftware.it", 5, 25);
    }
}

Sorvoliamo per ora sulla parola extends (legata al concetto di ereditarietà) e occupiamoci del metodo paint. Esso è un metodo che dobbiamo obbligatoriamente includere nelle nostre applet e che dovete dichiarare esattamente come è scritto nell’esempio. L’oggetto della classe Graphics definisce lo sfondo dell’applet su cui possiamo applicare tutti gli oggetti grafici, in questo caso aggiungiamo una stringa alle coordinate desiderate. Il metodo paint viene richiamato dall’interprete ogni volta che è necessario ridisegnare l’applet. Tuttavia non si tratta dell’unico metodo utile della classe Applet e molto spesso vengono utilizzati anche altri metodi. Il metodo public void init() ad esempio viene invocato ogni qualvolta l’applet venga caricata nel browser, ed è molto spesso usato per inizializzare alcuni parametri relativi ad esempio al colore o alle prime figure da disegnare nell’applet. Altri due metodi molto interessanti sono i metodi start() e stop() che vengono automaticamente invocati, ad esempio, se effettuiamo un cambio di finestra. Quando avviamo l’applet, infatti, se abbiamo il focus nella finestra dell’applet stessa viene invocato il metodo start, mentre quando spostiamo il focus su un’altra finestra (cioè clicchiamo su qualcos’altro) viene invocato il metodo stop() e l’applet rimane in attesa fino a che un nuovo click sulla finestra dell’applet riporta il focus sulla stessa generando quindi una nuova invocazione del metodo start(). Dovrebbe quindi essere chiaro che init() viene invocato una sola volta durante “la vita” di un’applet mentre start può essere invocato ripetute volte. Potete trovare un paio di esempi di semplici applet. Per comodità ho inserito anche le pagine HTML necessarie alla visualizzazione dell’applet.

Nelle lezioni successive ci occuperemo di approfondire alcuni aspetti del linguaggio cui abbiamo solo accennato e di affrontarne ex-novo degli altri. In particolare, qualora possibile, utilizzeremo sempre delle applet come esempi poiché si tratta di uno degli aspetti maggiormente utilizzati di Java.

Ti consigliamo anche

Link copiato negli appunti