


























Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Introduzione alla programmazione ad OO e a Java
Tipologia: Appunti
1 / 34
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!



























In offerta
1.1 Concetti di base sui computer COMPUTER (=) insieme componenti hw e sw. Hw indica la macchina fisica. PROGRAMMA (=) insieme istruzioni che un computer deve eseguire SW (=) indica tutti i possibili tipi di programmi utilizzati x fornire istruzioni a un computer.
1.1.1 Hardware e memoria Tutti i computer possiedono dispositivi di ingresso, di uscita e altri componenti presenti nel case che si occupano di archiviare i dati ed effettuare computazioni. CPU (=) è il processore ed è il dispositivo interno che esegue le istruzioni di un programma. Esso è in grado solo di eseguire istruzioni molto semplici e operazioni aritmetiche di base. MEMORIA (=) conserva i dati che il computer deve elaborare e risultati dei calcoli intermedi. Ci sono due tipi di memoria:
programma stesso. Le info presenti in tale memoria sono volatili (cancellate quando il pc viene spento)
RAM (=) memoria ad accesso casuale. Il byte è la più piccola unità di memoria indirizzabile. La memoria principale del computer è costituita da un lungo elenco di byte numerati, ognuno dei quali ha un proprio INDIRIZZO. Un byte è costituito da 8 bit i quali possono assumere valore 0 oppure 1. Un byte è sufficientemente grande per contenere un singolo carattere della tastiera. Per memorizzare una stringa di caratteri è necessario impiegare più byte. In tal caso il computer utilizza più byte adiacenti i quali vengono considerati un’area di memoria, dove l’indirizzo dell’area corrisponde all’indirizzo del primo byte. La memoria ausiliare viene utilizzata per conservare dati in modo permanente. Essa è suddivisa in byte i quali raggruppati formano i file. FILE (=) può contenere qualsiasi tipo di dato. Ha un nome e un gruppo di file può essere organizzato in directory o cartelle.
1.1.2 Programmi Quando si fornisce a un computer un programma e alcuni dati, si sta eseguendo (RUNNING) il programma sui dati. Ogni volta che si accende il computer si sta già eseguendo un programma, cioè il SO. SISTEMA OPERATIVO (=) programma supervisore che controlla funzionamento del computer nella sua interezza. Volendo eseguire un programma, si indica al so cosa si vuole fare. Quindi il so recupera il programma e lo avvia. Per richiedere al so di eseguire un programma è sufficiente cliccare con il mouse sull’icona desiderata.
1.1.3 Linguaggi di programmazione, compilatori e interpreti Linguaggi di programmazione moderni sono detti linguaggi di alto livello in quanto facili da utilizzare e comprendere. L’HW dei computer non è in grado di comprendere direttamente i linguaggi di alto livello, perciò deve essere prima tradotto in un altro linguaggi comprensibile per il computer. Linguaggio compreso dal computer è il linguaggio macchina cioè un linguaggio di basso livello. La traduzione da linguaggio di alto livello a linguaggio di basso livello, nella maggior parte dei casi, viene effettuata dal compilatore. COMPILATORE (=) elabora programma scritto in linguaggio di alto livello in modo tale che possa essere eseguito dal pc. Tale operazione è detta compilazione del programma. Una volta compilato, il programma risultante potrà essere eseguito quante volte si vuole senza doverlo ricompilare. Programma di input per compilatore -> programma sorgente Programma di output per compilatore -> programma oggetto. Compilatore Software che traduce un programma in linguaggio di alto livello in un programma in linguaggio di basso livello. Alcuni programmi di alto livello vengono tradotti dagli interpreti. Il compilatore traduce l’intero programma in una sola passata, la compilazione viene effettuata una sola volta e il programma oggetto può essere eseguito un numero indefinito di volte senza ricompilare. Interprete Programma che traduce ogni singola riga di codice e la esegue, quindi la traduzione si alterna all’esecuzione. Java utilizza un approccio che combina compilazione ed interpretazione (BYTECODE JAVA).
1.1.4 Bytecode Java Compilatore Java non traduce programma nel linguaggio macchina specifico del computer su cui è stato compilato, ma lo traduce in un programma detto bytecode. BYTECODE (=) linguaggio macchina di una macchina virtuale. Tradurre un programma scritto in bytecode nel linguaggio macchina è abbastanza semplice. Programma che effettua la traduzione è chiamato MACCHINA VIRTUALE JAVA oppure JVM.
linguaggio macchina Il vantaggio nell’utilizzare il bytecode java consiste nella portabilità. Bytecode E’ facile da tradurre nel linguaggio macchina di qualsiasi computer. Ogni tipo di computer impiegherà il proprio traduttore (INTERPRETE) che traduce istruzioni bytecode in istruzioni in linguaggio macchina di un certo computer. Si utilizzano due comandi: uno per compilare il programma sorgente java in bytecode e un altro per eseguire il programma. Il comando di esecuzione indica all’interprete di eseguire il bytecode.
1.1.5 Class Loader Solitamente un programma java è costituito da diverse porzioni dette classi. Esse sono scritte da autori diversi e compilate separatamente. Per eseguire il programma, i bytecode delle diverse classi devono essere collegati tra loro. Tale operazione di collegamento è effettuata dal CLASS LOADER ed è svolta automaticamente.
1.2 Un assaggio di Java 1.2.2 Applicazioni e applet Ci sono due tipologie di programmi java: le applicazioni e le applet. La differenza consiste nel fatto che le applicazioni sono create per essere eseguite localmente su un computer, mentre le applet sono create per essere inviate tramite internet ed eseguite in un computer remoto.
1.2.3 Il primo programma Java Import java.util.Scanner; -> indica al compilatore che il programma usa la classe Scanner java.util -> è un package, cioè una libreria di classi definite in precedenza Per acquisire dati da tastiera: Scanner tastiera = new Scanner(System.in); n = tastiera.nextInt(); -> se dobbiamo acquisire interi All’interno delle classi sono presenti i metodi, il più importante è il metodo main. Ogni istruzione all’interno di un metodo definisce un compito e l’insieme delle istruzioni costituiscono il corpo del metodo. Per eseguire le azioni, i programmi java utilizzano oggetti software, detti anche oggetti. Le azioni sono definite dai metodi. Gli eventuali elementi tra parentesi sono detti argomenti e forniscono al metodo l’informazione di cui necessita per eseguire una determinata azione. Un oggetto esegue un’azione quando viene invocato uno dei suoi metodi e per farlo si scrive il nome dell’oggetto seguito da un punto e dal nome del metodo. EX. System.out.println(“Ciao!”); -> System = CLASSE, out = OGGETTO, println = METODO INVOCATO SULL’OGGETTO, ciao = ARGOMENTO Variabile (=) può memorizzare dati e bisogna specificarne il tipo.
1.2.4 Scrivere, compilare ed eseguire programmi Java Ogni definizione di classe viene scritta su un file distinto, il quale avrà estensione .java e il nome della classe stessa (PrimoProgramma.java). Prima di poter eseguire il programma java, le classi dovranno essere tradotte in un linguaggio comprensibile dal computer tramite il compilatore. Per compilare solo una classe -> javac PrimoProgramma.java Se si compila tale classe, il bytecode risultante avrà estensione .class e quindi PrimoProgramma.class
TIPO (=) specifica insieme di valori ed operazioni che possono essere eseguite su di esso. I tipi di dato principali in java sono:
lettera. Per interi -> byte, short, int, long, double, float. Boolean, char.
2.1.3 Identificatori java Con il termine identificatore ci si riferisce al nome che viene dato ad una variabile. Può essere composto solo da lettere, cifre e da _. Nessun nome può contenere spazi o caratteri come. o *. Java è case sensitive. Alcuni termini come IF oppure i tipi primitivi sono detti parole chiave o parole riservate.
2.1.4 Istruzioni di assegnamento Il simbolo = viene utilizzato come operatore di assegnamento. Tale istruzione indica al pc di cambiare il valore memorizzato nella variabile a sinistra dell’uguale. Essa termina con ;. Quando tale istruzione viene eseguita, il computer valuta prima l’espressione a destra per calcolarne il valore, poi assegna il risultato alla variabile a sinistra. L’operatore di assegnamento richiede al computer di rendere la variabile uguale al valore dell’espressione calcolato. Le istruzioni di assegnamento che coinvolgono tipi primitivi sono del tipo -> var = expr; Una volta dichiarate, le variabili devono essere inizializzate.
2.1.7 Costanti Le costanti o letterali sono elementi il cui valore non può cambiare nel tempo
2.1.8 Costanti con nome Esse vengono dichiarate in tal modo -> public static final double PI = 3.14159; Il nome è sempre tutto maiuscolo.
2.1.9 Compatibilità di assegnamento Quando si utilizzano variabili numeriche, a volte, vengono effettuate delle conversioni automatiche da un tipo ad un altro. Tale conversione è automatica quando si assegna un int ad un double. Byte -> short -> int -> long -> float -> double Per assegnare un valore double ad un int (in tal caso la conversione non è automatica), viene effettuata una conversione di tipo (TYPE CAST).
2.1.10 Conversioni di tipo Double distanza = 9.5; int punti = distanza; Si tratta di un assegnamento illecito. Per renderlo possibile si effettua un cast: int punti = (int)distanza; -> IN TAL MODO DISTANZA DA ESSERE DOUBLE DIVENTA INT. Una conversione di tipo non altera la variabile di origine. La conversione di tipo effettua un troncamento! Convertire un carattere in intero -> char simbolo = ‘7’; System.out.println((int)simbolo);
2.1.11 Operatori aritmetici I cinque operatori aritmetici possono essere utilizzati con operandi di tipo intero, in virgola mobile e il risultato dell’operazione dipenderà dal tipo degli operandi. Poniamo di effettuare un’addizione tra due operandi di tipo differente, uno in virgola mobile e uno di tipo intero. Il tipo del risultato sarà in virgola mobile (coercizione di tipo). Oltre agli usuali operatori aritmetici, java ne introduce un quinto: & (=) operatore resto. Viene solitamente usato con operandi di tipo intero. I simboli + e – sono anche operatori unari, cioè un operatore che possiede un solo operando. L’operatore binario, invece, ha due operandi.
2.1.12 Parentesi e regole di precedenza
Con l’aiuto delle parentesi è possibile indicare al compilatore quali operazioni svolgere per prime, quali per seconde e così via. Quando le parentesi vengono omesse, il compilatore esegue prima la moltiplicazione e poi l’addizione. Quindi il computer, in mancanza di parentesi, esegue le operazioni in base alle regole di precedenza e gli operatori messi più in alto hanno una precedenza maggiore. Le operazioni binarie tra operatori con la stessa precedenza sono eseguite da sinistra a destra; le operazioni unarie, invece, sono eseguite da destra a sinistra. E’ necessario precisare che troppe parentesi potrebbero pregiudicare la comprensibilità dell’espressione.
2.1.13 Operatori di assegnamento ausiliari L’operatore di assegnamento = può essere preceduto da altri operatori, ad esempio +, per svolgere un assegnamento e, contemporaneamente, l’operazione indicata dall’operatore inserito. Ad esempio sum= sum + 5 corrisponde a sum += 5.
2.1.14 Operatori di incremento e decremento OPERATORE DI INCREMENTO (=) si scrive come ++ ed incrementa di un’unità il valore di una determinata variabile. OPERATORE DI DECREMENTO (=) si scrive come -- e decrementa di un’unità il valore di una variabile. Vengono per lo più utilizzati con variabili di tipo intero. Entrambi possono essere posti prima o dopo una variabile. Quando vengono posti prima di una variabile, si usa la forma prefissa, nel caso contrario, invece, si usa la forma postfissa.
2.2. La classe String 2.2.1 Stringhe costanti e variabili Un valore di tipo String è una stringa racchiusa tra doppi apici. E’ una sequenza di caratteri considerati come se fossero un singolo elemento. Per dichiarare una variabile di tipo String-> String nome; nome = “Daniela”; -> per l’assegnazione. Una stringa può anche non contenere caratteri cioè una stringa vuota e viene indicata in tal modo: “”;
2.2.2 Concatenazione di stringhe Viene effettuata con l’operatore +. Saluto = “ciao”; frase = saluto + “Daniela”;
2.2.3 Metodi di String Una variabile String è un oggetto appartenente alla classe String e gli oggetti possiedono metodi e dati. I metodi forniti dalla classe String consentono di elaborare dati. “ciao”. length(); -> restituisce la lunghezza della stringa “ciao”. Vengono contati anche gli eventuali spazi. INDICE (=) posizione di un carattere nella stringa SOTTOSTRINGA (=) indica una porzione di una stringa. Il metodo indexOf restituisce l’indice di una sottostringa passata come argomento. frase. indexOf(“bello”); -> frase = “Java è bello” e il risultato del metodo sarà 8.
2.2.4 Elaborazione delle stringhe Java possiede un’altra classe chiamata StringBuilder la quale possiede metodi per modificare i dati dei propri oggetti.
2.2.5 Carattere di escape System.out.println(“Il linguaggio “Java” è il nome di un linguaggio”). Tale scrittura genera errore, per questo si utilizza il backslash() -> (“Il linguaggio \“Java\” è il nome di un linguaggio”). CARATTERI DI ESCAPE (=) \” \’ \ \n \r \t
2.2.6 Set di caratteri Unicode Un set di caratteri è una lista di caratteri a ciascuno dei quali è associato un numero. Il set di caratteri ASCII include tutti i caratteri normalmente usati su una tastiera inglese.
3.2 Tipo boolean 3.2.1 Variabili booleane If (x == true) si può scrivere if(x), mentre if(x==false) si può scrivere if(!x).
3.2.2 Regole di precedenza
VALUTAZIONE A CORTO CIRCUITO (=) se in un’espressione booleana A||B, A è vera e quindi java conclude che l’intera espressione è vera, senza valutare l’espressione B. Lo stesso vale per l’espressione A&&B se A è falsa, allora l’intera espressione è falsa.
La classe Scanner possiede un metodo .nextBoolean() per leggere un valore di tipo boolean.
3.3 Istruzione switch Switch(espressione_di_controllo){….} All’interno delle graffe sono presenti le diverse azioni: case etichetta_case: elenco_istruzioni; Al termine di ogni case è presente un break; che comporta il termine dello switch. Se nessun case corrisponde al valore dell’espressione di controllo, è previsto un case default che stamperà un messaggio di errore. L’espressione da controllare può essere una stringa, un valore numerico ma può contenere anche operatori aritmetici.
3.3.1 Enumerazioni Per restringere il contenuto di una variabile a un certo insieme di valori, si può definire la variabile come di tipo enumerazione. enum PunteggioFilm {E, B, P} L’enumerazione si comporta come un tipo classe. PunteggioFilm punteggio; -> variabile di tipo enum Per assegnare B a punteggio si può scrivere: punteggio = PunteggioFilm.B; Avremmo potuto scrivere anche enum PunteggioFilm {ECCELLENTE, BUONO, PESSIMO}
4.1 Cicli in Java CICLO (=) parte del programma che ripete un gruppo di istruzioni CORPO (=) gruppo di istruzioni ripetuto nel ciclo ITERAZIONE (=) ripetizione del corpo del ciclo
4.1.1 Istruzione while Un ciclo while ripete più e più volte l’azione definita nel corpo finchè l’espressione booleana di controllo rimane vera. Quando l’istruzione diventa falsa, la ripetizione termina. While(espressione booleana) {……} Il corpo di un ciclo while può essere ripetuto anche zero volte.
4.1.2 Istruzione do-while La differenza con il ciclo while è che il corpo di un ciclo do-while viene eseguito sempre almeno una volta. Dopo aver eseguito il corpo del ciclo viene valutata l’espressione booleana di controllo: se è vera, il corpo viene eseguito nuovamente, altrimenti il ciclo termina. Do {….} while (espressione booleana);
Un problema molto comune nei programmi è rappresentato dai cicli che non terminano mai, ma che continuano a ripetere all’infinito il proprio corpo. Un ciclo che ripete il proprio corpo senza mai terminare è chiamata ciclo infinito.
4.1.3 Istruzione for For(inizializzazione; espressione booleana; aggiornamento) {….}
4.1.4 Dichiarare variabili all’interno di un’istruzione for Dichiarare una variabile all’interno di un’istruzione for, significa che tale variabile è locale, cioè non può essere usata al di fuori del ciclo. La porzione di programma in cui è disponibile una variabile è detta visibilità della variabile
4.1.5 Usare una virgola in un’istruzione for Per usare più istruzioni di inizializzazione basta separare le istruzioni con una virgola. La virgola utilizzata in questo contesto è detta operatore virgola.
4.1.6 Istruzione for-each E’ un’altra forma di ciclo for da utilizzare quando si deve operare su tutti gli elementi di una collezione di dati. enum Seme {CUORI, QUADRI, PICCHE, FIORI} for (Seme semeSuccessivo : Seme.values()) System.out.println(semeSuccessivo + “ “); System.out.println();
Seme.values() -> rappresenta tutti i valori dell’enumerazione. La variabile semeSuccessivo assume ognuno dei valori dell’enumerazione a mano a mano che l’iterazione procede.
4.2.3 Controllare il numero di iterazioni in un ciclo Double prossimo, media, somma=0; for(int cont = 1; cont <= nStudenti; cont++){ prossimo = tastiera.nextDouble(); somma += prossimo; } If(nStudenti > 0) Media = somma/nStudenti; else System.out.println(“Nessun punteggio disponibile per calcolare la media”);
Cicli come questo in cui si conosce esattamente il numero di iterazioni prima di eseguire il ciclo, sono chiamati cicli count-controlled. Purtroppo non è sempre possibile conoscere a priori il numero di iterazioni da compiere. Per capire quando terminare un’iterazione bisogna chiedere all’utente se sia giunto il momento di farlo. Questa tecnica è detta ask before iterating. Un valore sentinella, invece, è utilizzato per indicare la fine dell’input.
4.2.4 Istruzione break e continue nei cicli Quando viene eseguito l’istruzione break, il ciclo che la contiene termina immediatamente, senza eseguire l’eventuale parte rimanente del corpo del ciclo. L’introduzione dell’istruzione break può complicare la comprensione del ciclo. L’istruzione continue all’interno del ciclo termina, invece, dopo l’iterazione corrente e passa a quella successiva. Anche l’istruzione continue genera problemi di comprensione.
5.1.2 Definire metodi che restituiscono un valore public static double area Cerchio() {…} -> definizione metodo che restituisce valori L’unica differenza con un metodo di tipo void, consiste nel fatto che al posto della parola void è presente il nome del tipo di ritorno. Alla fine del corpo del metodo, ci sarà un return espressione; Un metodo che restituisce un valore può essere invocato in qualsiasi punto del codice. Per invocarlo:
5.1.3 Variabili locali Una variabile locale può essere utilizzata esclusivamente all’interno del metodo che l’ha definita.
5.1.4 Blocchi BLOCCO (=) insieme istruzioni racchiuso tra {} Se si dichiara una variabile all’interno di un blocco, la variabile è locale al blocco, cioè ha significato solamente all’interno del blocco. Inoltre sappiamo che la porzione di programma in cui una variabile ha significato è detta visibilità della variabile (scope). Al termine del blocco, tutte le variabili dichiarate al suo interno scompaiono, quindi è possibile usare lo stesso nome, successivamente, per definire un’altra variabile al di fuori del blocco.
5.1.5 Parametri di tipo primitivo public static double areaCerchio (double raggio) raggio : è un parametro formale. Rappresenta un sostituto temporaneo di un valore effettivo che sarà disponibile solo una volta invocato il metodo. Il valore effettivo è detto argomento oppure parametro attuale. Il parametro attuale è quello presente tra le parentesi nel momento in cui in metodo viene invocato. Passaggio per valore: meccanismo di assegnamento degli argomenti ai parametri formali che utilizza il valore dell’argomento stesso. E’ l’unico meccanismo usato per passare argomenti di tipo primitivo. Il parametro formale che compare nella definizione del metodo è una variabile locale che viene inizializzata al valore dell’argomento fornito nell’invocazione del metodo. Se come argomento si una variabile di tipo primitivo, l’invocazione del metodo non può cambiare il valore dell’argomento proprio perché il passaggio avviene per valore. Il numero di parametri attuali deve essere uguale al numero di parametri formali.
5.1.6 Istruzione return E’ preferibile utilizzare una sola istruzione return.
5.3 Cosa accade realmente quando si invoca un metodo? Quando si invoca un metodo viene creato in memoria un record di attivazione, contenente tutte le info necessarie per gestire il metodo invocato. Un rda contiene dati relativi al metodo e info per la gestione dei metodi da esso eventualmente invocati. Le info relative al metodo invocato includono parametri formali e le variabili locali. Le info per la gestione dei metodi da esso invocati includono l’indirizzo di ritorno (quale istruzione eseguire nel momento in cui il metodo invocato termina) e il risultato. Il rda viene creato dinamicamente nel momento in cui il metodo viene chiamato e viene posto in cima allo stack. Rimane nello stack fino a quando non viene rimosso in quanto terminato. Metodi che invocano altri metodi danno vita ad una sequenza di rda gestiti secondo la politica LIFO (last in first out).
5.4.3 Collaudare i metodi TESTING BOTTOM-UP (=) collaudo dal basso verso l’alto STUB (=) versione semplificata di un metodo che non può essere utilizzata all’interno del programma finale, ma è sufficiente per permettere il collaudo del sistema ed è abbastanza semplice da creare.
6.1.1 Creazione ed accesso ad un array ARRAY (=) collezione di elementi dello stesso tipo. tipo [] nome_array = new tipo[dimensione]; -> CREAZIONE nome_array[indice] = tastiera.nextTipo(); -> ACQUISIZIONE Gli indici degli array partono da 0. Java alloca a run time la memoria per un array. Quindi, se non si conosce la dimensione dell’array a priori, è possibile inserirla da tastiera durante l’esecuzione del programma.
6.1.3 La proprietà length Nome_array.length() -> lunghezza dell’array
6.1.4 Ulteriori dettagli sugli indici di un array Un errore di programmazione comune quando si usano gli array è l’utilizzo, all’interno delle parentesi quadre, di espressioni che restituiscono indici non validi per l’array considerato. Se l’indice restituito da un’espressione non è compreso fra 0 e nome_array.length -1, si dice che l’indice dell’array è fuori dai limiti (array index out of bounds) o non valido. Anche se il codice contiene un indice non valido, viene comunque compilato senza alcun errore, ma si avrà un errore a run-time. 6.1.5 Inizializzare gli array Può essere inizializzato in fase di dichiarazione altrimenti vengono inizializzati col valore di default del loro tipo base.
6.1.6 Array parzialmente riempiti Quando la collezione di dati di un array non è piena, allora si tratta di un array parzialmente riempito. In alcune situazioni non è necessario che l’array sia totalmente riempito. Quando l’array è parzialmente riempito, è necessario tenere traccia di quanto l’array sia utilizzato e solitamente si utilizza una variabile intera che man mano che vengono inseriti gli elementi viene incrementata. La capacità dell’array a è esattamente pari ad a.length().
6.1.7 Utilizzare il ciclo for-each con gli array Si tratta di un ciclo for potenziato. double [] a = new double[10]; for(double elemento : a){ System.out.prinln(elemento); }
6.2 Utilizzare gli array nei metodi 6.2.1 Variabili indicizzate come argomenti di un metodo double media = getMedia(punteggio, punteggioSeguente[i]); Le variabili indicizzate vengono trattate come variabili del tipo base dell’array.
6.2.2 Array come argomenti di un metodo public static void incrementaArray(double [] a){…} Non si deve specificare la dimensione dell’array nell’intestazione del metodo.
6.2.3 Argomenti del metodo main public static void main(String [] args); String [] args -> args è un array di tipo String. Il metodo main viene invocato automaticamente e come argomento gli viene fornito un array di stringhe di default. E’ però possibile fornire delle stringhe come argomento del programma e queste stringhe entrano automaticamente a far parte dell’array args. Si passano argomenti a un programma quando lo si esegue da linea di comando: java ProgrammaDiProva Mario Rossi
a[j] = temp; } }
6.3.2 Altri algoritmi di ordinamento Il selection sort non è l’algoritmo di ordinamento più efficiente, ma è sicuramente il più facile da implementare e che ci garantisce di non commettere errori. La classe Arrays del package java.util definisce il metodo statico sort.
6.3.3 Ricerca negli array Se è necessario effettuare la ricerca di un elemento all’interno di un array, si può utilizzare la ricerca sequenziale. Si confrontano tutti gli elementi dell’array con l’elemento cercato per vedere se quest’ultimo è contenuto nell’array. La ricerca termina quando viene trovare l’elemento oppure quando termina l’array. La ricerca sequenziale può essere applicata ad array anche se non è ordinato.
6.4 Array multidimensionali Nome_array[indice_riga][indice_colonna];
6.4.1 Fondamenti su array multidimensionali Int [ ] [ ] tabella = new int[10][6]; Per esaminare l’array multidimensionale vengono utilizzati due cicli for innestati: uno per scorrere le righe, l’altro per scorrere le colonne.
6.4.2 Array multidimensionali come parametri e come valori restituiti int [ ] [ ] a -> come parametro nella definizione di un metodo return temp -> come valore restituito dove temp è un array multidimensionale (int [ ] [ ] temp = new int[righe][col])
6.4.3 Rappresentazione java di array multidimensionali Un array multidimensionale viene rappresentato come array di array. a.length - > numero righe; a[riga].length -> numero colonne.
6.4.4 Array irregolari Int [ ][ ] a = new int [3][5]; TALE ISTRUZIONE E’ EQUIVALENTE ALLE SEGUENTI ISTRUZIONI: int [ ][ ] a; a = new int [3][ ]; -> dichiara a un array di lunghezza 3i cui elementi possono essere array di qualsiasi lunghezza a[0] = new int[5]; -> creano array di interi di lunghezza 5 a[1] = new int[5] a[2] = new int[5]; Tutto ciò corrisponde al dichiarare un array bidimensionale con 3 righe e 5 colonne (=) ARRAY IRREGOLARI. In tal caso, ogni riga (a[0], a[1], a[2]) avrà un numero di elementi diversi (in questo caso hanno tutte 5 elementi).
7.1 Le basi della ricorsione Quando una parte di un algoritmo costituisce una versione ridotta dell’algoritmo completo, quest’ultimo è definito ricorsivo. Un algoritmo ricorsivo può essere implementato tramite un metodo ricorsivo, cioè un metodo che contiene al suo interno una chiamata a se stesso. Per scrivere un metodo ricorsivo è necessario stabilire quale sia il caso base, nonché il caso di arresto. public class ContoAllaRovesciaRicorsivo { public static void main (String [ ] args){ contoAllaRovescia (3); }
public static void contoAllaRovescia (int num) {
if (num <= 0){ System.out.println(); }else{ System.out.print(num); contoAllaRovescia (num – 1); } } } Quando si incontra una chiamata ricorsiva, l’elaborazione viene sospesa temporaneamente, visto che per procedere è necessario conoscere il risultato della chiamata ricorsiva. E’ necessario prevedere:
risolvere una o più versioni ridotte del problema originale;
base).
7.1.2 Ricorsione infinita Si ha quando non si prevedono uno o più casi base che, per opportuni valori degli argomenti, arrestino la sequenza di chiamate ricorsive.
7.1.3 Lo stack e la ricorsione Le chiamate ricorsive sono chiamate a metodi e l’invocazione di un metodo comporta la creazione di un rda nello stack. Con lo stack il computer può tener traccia facilmente dei risultati delle chiamate ricorsive. Quando il computer incontra una chiamata ricorsiva, interrompe l’esecuzione in corso su quel rda per determinare il risultato della chiamata ricorsiva. Prima di fare questo, però, salva le info necessarie per poter continuare l’elaborazione rimasta in sospeso. Queste info vengono scritte su un nuovo rda che viene posto al top dello stack. Il computer sostituisce su nuovo rda i parametri con gli argomenti passati al metodo e inizia l’esecuzione della chiama ricorsiva. Questo procedimento prosegue finché qualche chiamata ricorsiva del metodo non completa la propria elaborazione senza produrre altre chiamate ricorsive. A tal punto il computer completa le elaborazioni lasciate in sospeso ed elimina il rda creato con le info. In qualsiasi momento, l’unico record accessibile è quello posto in cima alla pila. Stack overflow -> si verifica quando qualche metodo ha generato una sequenza eccessivamente lunga di chiamate ricorsive.
7.1.4 Confronto tra metodi ricorsivi ed iterativi Un metodo ricorsivo utilizza più memoria rispetto ad una versione iterativa e quindi la sua esecuzione può essere più lenta.
8.1 Definire classi CLASSE (=) definizione di un tipo di oggetto. OGGETTO (=) istanza di una classe. Si possono creare più oggetti della stessa classe. Una classe specifica gli attributi degli oggetti della classe. La definizione della classe Automobile indica che un suo oggetto deve avere 3 attributi: livello carburante, velocità, targa. La definizione di una classe non specifica il valore degli attributi in quanto questi sono specifici dei singoli oggetti. Una classe specifica le azioni compiute dagli oggetti attraverso la definizione di metodi. I progettisti utilizzano il diagramma delle classi UML per descrivere classi, oggetti e metodi.
Nome classe: Automobile
Attributi:
Metodo d’accesso (metodo get) -> metodo che permette di osservare quali sono i dati contenuti in una variabile. Metodi di modifica (metodo set) -> metodi che permettono di modificare i dati memorizzati nelle variabili. Esso può verificare se un cambiamento è appropriato e notificare l’utente in caso di problemi.
8.2.5 La parola chiave this applicata alle variabili di istanza All’interno di un blocco non possono coesistere due variabili che hanno lo stesso nome, quindi anche all’interno di un metodo non possono esserci due variabili con lo stesso nome. Per permettere a due variabili con lo stesso nome di coesistere nello stesso metodo, è necessario che una sia una variabile di istanza e che l’altra sia una variabile locale al metodo. Per far riferimento ad una variabile di istanza si utilizza il this -> this.nome_variabile_istanza
8.2.6 Metodi che invocano altri metodi Il corpo di un metodo può contenere l’invocazione di un altro metodo. Tuttavia, se il metodo invocato si trova nella stessa classe, l’invocazione viene effettuata senza scrivere il nome dell’oggetto. Un metodo alternativo è quello di scrivere this.nome_metodo(), nel quale this va a sostituire il nome dell’oggetto che viene ricevuto dal metodo.
8.2.7 Incapsulamento Secondo l’incapsulamento, per conoscere un certo componente software, un programmatore non ha bisogno di conoscere tutti i dettagli della sua definizione. L’incapsulamento è una forma di information hiding. Affinchè l’incapsulamento sia utile, la definizione di una classe deve essere tale per cui un programmatore possa usarla senza conoscerne i dettagli. L’incapsulamento deve separare la definizione di una classe in due parti: l’interfaccia e l’implementazione. INTERFACCIA (=) indica ai programmatori ciò di cui hanno bisogno per usare la classe nei loro programmi. Essa consiste nell’intestazione dei suoi metodi pubblici e delle sue costanti pubbliche. IMPLEMENTAZIONE (=) tutti gli elementi privati della classe.
classe senza descrivere come lo fa
metodo
8.3 Oggetti e riferimenti 8.3.1 Variabili di tipo classe Le variabili di tipo classe forniscono un nome agli oggetti e contengono l’indirizzo di memoria dell’oggetto cui fa riferimento la variabile. L’oggetto stesso è memorizzato in un’altra area di memoria e l’indirizzo di tale area è detto riferimento all’oggetto. TIPI RIFERIMENTO (=) tipi classe. E’ un tipo le cui variabili contengono riferimenti, quindi indirizzi di memoria invece di valori. == controlla che due variabili abbiano lo stesso indirizzo di memoria.
8.3.2 Definire metodo equals per una classe Per verificare se due oggetti sono uguali, secondo una propria concezione di uguaglianza, si implementa un metodo equals. Il metodo equals di una classe solitamente è di tipo boolean e restituisce sempre un valore falso o true. s1. equals (s2) -> invoca metodo equals su oggetto s1 passando come parametro di confronto s2.
8.3.4 Test di unità TEST DI UNITA’ (=) il programmatore verifica la correttezza di singole unità di codice. Un’unità è generalmente costuita da un metodo, ma potrebbe anche essere una classe.
SUITE DI TEST (=) collezione di test di unità. Ogni test è automatizzato e il processo di esecuzione ripetuta dei test è detta test di regressione. Un tipo di test da considerare potrebbe essere il test negativo. Esso è un test volto a verificare che il programma non termini in modo inatteso se gli vengono forniti dati di input con caratteristiche diverse da quelle attese.
8.3.5 Parametri di tipo classe Quando si usa un operatore di assegnamento con oggetti di tipo classe, si copia un indirizzo di memoria. I parametri formali sono definiti tra parentesi dopo il nome del metodo. Un parametro formale di tipo classe è una variabile locale che contiene l’indirizzo di memoria di un oggetto del tipo classe specificato dal parametro. Quando viene invocato il metodo, il parametro viene inizializzato con l’indirizzo di memoria dell’argomento passato nell’invocazione del metodo.
9.1 Costruttori Quando si crea un oggetto di una classe utilizzando l’operatore new, si invoca un particolare tipo di metodo chiamato costruttore.
9.1.1 Definire i costruttori COSTRUTTORE (=) particolare metodo invocato quando si utilizza operatore new per creare un nuovo oggetto. Specie specieTerrestre = new Specie(); Specie specieTerrestre -> dichiara che la variabile specieTerrestre è un riferimento ad un oggetto della classe Specie new Specie() -> crea ed inizializza un nuovo oggetto il cui indirizzo viene assegnato a specie Terrestre Specie () -> chiamata al costruttore che java ha fornito automaticamente alla classe. Le parentesi sono vuote perché questo costruttore non ha argomenti. Un costruttore può eseguire qualsiasi azione inserita nella sua definizione, anche se esso ha essenzialmente il compito di eseguire azioni di inizializzazione. Hanno lo stesso compito del metodo set, ma oltre ad inizializzare un oggetto lo creano. Essi possono avere parametri. Ogni costruttore deve avere lo stesso nome della sua classe. I costruttori possono avere più definizioni con un differente tipo e numero di parametri. I costruttori non contengono la parola void e non hanno return. Se il costruttore non inizializza una particolare variabile, lo farà java con un valore di default. COSTRUTTORE DI DEFAULT (=) costruttore senza parametri. Quando si crea un oggetto utilizzando l’operatore new occorre sempre includere l’invocazione a uno dei costruttori definiti nella classe. Come per ogni invocazione di metodo, bisogna indicare la lista degli argomenti tra parentesi dopo il nome del costruttore. Un’invocazione ad un costruttore restituisce un riferimento, cioè l’indirizzo di memoria di un oggetto. Per modificare valori, invece, viene utilizzato il metodo set.
9.1.2 Invocare metodi da costruttori Un costruttore può invocare metodi definiti al suo interno. Bisogna fare attenzione quando i costruttori invocano metodi pubblici delle proprie classi. Il problema ha a che fare con l’ereditarietà. Infatti, un’altra classe può alterare il comportamento dei metodi pubblici e, di conseguenza, può alterare accidentalmente il comportamento di un costruttore. SOLUZIONE -> definire come privato ogni metodo invocato ogni costruttore.
9.1.3 Invocare un costruttore da un altro costruttore Per invocare un costruttore in un altro costruttore, si usa la parola chiave this: public Animale (String nome, in eta, double peso) { set(nome, eta, peso); }
public Animale (in eta) { this(“Nessun nome”, eta, 0); }
Java introduce una classe wrapper anche per il tipo primitivo boolean -> Boolean. Esso ha due costanti: Boolean.TRUE, Boolean.FALSE
9.3 Overloading 9.3.1 Concetti di base dell’overloading OVERLOADING (=) si verifica quando si assegna lo stesso nome a due o più metodi all’interno di una stessa classe. Per compiere questa operazione è necessario che le definizioni dei diversi metodi abbiano delle differenze nell’elenco dei parametri che ricevono. Se si effettua l’overloading di un nome di metodo, cioè se si assegna lo stesso nome a più definizioni di metodi di una stessa classe, java distingue i metodi sulla base del numero di parametri che ricevono e dei tipi di parametri. Se non esiste alcun metodo che corrisponde al metodo invocato, allora java prova ad eseguire automaticamente alcune delle conversioni di tipo. Se non c’è alcuna corrispondenza nemmeno in questo caso, java restituisce un errore durante la compilazione. FIRMA (=) nome di un metodo, il numero e il tipo di parametri. Regola overloading -> tutti i metodi di una classe devono avere firme diverse. L’overloading può essere applicato a qualsiasi tipo di metodo: void o metodi che restituiscono valori. Può essere applicato anche ai costruttori.
9.3.2 Overloading e conversione automatica di tipo Java cerca di usare l’overloading prima di usare la conversione automatica di tipo. Se java individua una definizione di metodo che corrisponde al tipo di argomenti fornito, utilizza tale definizione. Java non effettua una conversione automatica di tipo degli argomenti passati finchè non si accerta che non esista una definizione di metodo che corrisponde al tipo degli argomenti passati al metodo.
9.3.3 Overloading e tipo di ritorno Non si può effettuare l’overloading di un nome di metodo fornendo due definizioni la cui intestazione differisce solo per il tipo del valore restituito. Una classe non può contenere metodi che hanno lo stesso nome e gli stessi parametri e solo valori restituiti differenti. Questi metodi, infatti, avrebbero la stessa firma e in java non si possono avere più metodi con la stessa firma.
9.4 Information hiding rivisitato 9.4.1 Privacy leak Una classe può avere variabili di istanza di qualsiasi tipo, anche di tipo classe. PRIVACY LEAK (=) falla nella sicurezza. Bisogna evitare che qualsiasi altra classe acceda alle variabili di istanza private di una classe. Infatti, una variabili di istanza privata di tipo classe referenzia un oggetto che, in alcuni casi, potrebbe essere modificato dall’esterno della classe (DOBBIAMO EVITARLO!). Per evitare questo problema possiamo:
restituiscono individualmente gli attributi interni di tali oggetti
stesso. CLONE (=) viene definito un metodo che crea un esatto duplicato di un oggetto referenziato.
9.5 Rappresentare in UML le relazioni associative fra classi RELAZIONE ASSOCIATIVA (=) sussiste ogni volta che all’interno delle classi vengono definite variabili di istanza di tipo classe. Una relazione associativa è una relazione has-a.
NAVIGABILITA’ (=) specifica la direzione di lettura dell’associazione. Può essere non specificata, unidirezionale, bidirezionale. Quando non è specificata non fornisce alcuna info utile per la codifica; quando è unidirezionale permette di identificare in quale classe saranno definite le variabili di istanza dell’altra classe; quando è bidirezionale, infine, specifica che le variabili di istanza saranno presenti in entrambe le classi. CARDINALITA’ (=) permette di specificare quante istanze entrano in gioco in un’associazione.
Persona
RUOLO (=) specifica la funzione che una classe svolge nei confronti della classe con cui è in associazione. Esso, quindi, non è altro che un nome ed è possibile assegnare ruoli ad entrambi gli estremi di un’associazione. Dal punto di vista implementativo, il ruolo specifica il nome che deve essere assegnato alla variabili di istanza che realizza l’associazione.
Automobile
Il verso della freccia ci indica che sarà la classe Persona a contenere le istanze della classe Automobile. 0..1 -> cardinalità. Una persona può non possedere un’automobile (0) o al massimo ne può possedere una (1) -automobile -> ruolo, cioè nome della variabile di istanza che realizza l’associazione e presente nella classe Persona P.S. scrivendo 1..* indichiamo che la cardinalità è compresa tra 1 ed un numero che non conosciamo (n).
9.6 Array nelle definizioni di classe 9.6.1 Array di tipi primitivi Esempio -> int [ ] a = new int [10];
9.6.2 Array di riferimenti Esempio -> Specie [ ] esemplare = new Specie [10]; -> dove Specie è una classe Gli elementi di tale array sono dei riferimenti ad oggetti di tipo Specie. Gli array di questo tipo, allo stesso modo degli array di tipo primitivo, sono inizializzati al valore di default (null). Anche con gli array si può verificare il fenomeno della privacy leak (variabile di istanza privata di tipo array che viene modificata all’esterno della classe di appartenenza). Tale fenomeno viene risolto nello stesso modo in cui lo si risolve nel caso di variabili di istanza private di tipo primitivo.
9.7 Enumerazioni come classi enum Semi {FIORI, QUADRI, CUORI, PICCHE} In tal caso il compilatore crea la classe Semi e i valori elencati sono i nomi di oggetti pubblici e statici di cui il tipo è Semi. La classe Semi ha metodi definiti: equals, compareTo, ordinal, toString, valueOf. Semi s = Semi.QUADRI;
0..1-automobile