Programmazione 2
Allocazione memoria
- Stack = variabili automatiche delle funzioni
- Heap = allocazione dinamica
- Static = per dati globali e inizializzati
Funzioni ricorsive -> funzione può richiamare se stessa. Ogni chiamata crea un nuovo frame dello stack che contiene info necessaria per quella particolare istanza della funzione.
Variabili globali -> valore visibile a tutte le funzioni (side effects). Da evitare, perché violano il principio dell’information hiding, comportano gestione difficile di grandi progetti (Java non le supporta).
Variabili automatiche -> esistono localmente nella funzione/metodo in cui vengono dichiarate. Vengono eliminate automaticamente. Schermano le variabili globali e si schermano fra loro.
Principi di Parnas: una funzione ha info necessarie a realizzare funzione e nulla più; implementatore di una funzione deve dare all’utente le info necessarie ad usare la funzione e nulla più.
Esercizi
- L’output è a=1, perché sto passando ‘a’ per copia e non per indirizzo.
- Se voglio che mi restituisca a incrementato devo passare parametri per indirizzo: void incrementa(int* x){*x=*x+1;}
- E devo passare alla funzione incrementa &a
Allocazione dinamica in C++ = new e delete
Caratteristiche Java
Per ogni tipo è definito un valore di default.
Tipi di riferimento: tipi array, tipi definiti dall’utente: classi e interfacce (es: Point punto = new Point(10,10);)
Attributi = costituiscono lo stato degli oggetti istanziati a partire dalla classe (valore diverso per ogni oggetto)
Metodi = definiscono comportamento degli oggetti istanziati a partire dalla classe (codice è lo stesso per ogni oggetto)
Istanze di una classe = oggetti
Ogni variabile il cui tipo è una classe contiene un riferimento ad un oggetto => gli oggetti sono accessibili solo per riferimento.
Ad ogni variabile di riferimento può essere assegnato null, es: Point p = null;
Manca aritmetica dei puntatori.
Passaggio parametri
- Parametri tipi primitivi -> passati per copia
- Parametri tipo riferimento (classi, interfacce, array) -> passati per riferimento
- Oggetti sono sempre passati per riferimento.
Pila
Funzione inserisci: funzione cresci: Private => funzione non accessibile da altre classi.
This => contiene riferimento a oggetto su cui è invocato il metodo.
Uso di inserisci: creazione oggetti con new -> viene invocato costruttore. 2 operazioni: allocazione della memoria per contenere oggetto, inizializzazione dello spazio allocato.
Non c’è distruttore => garbage collector: interviene automaticamente; può essere attivato con System.gc(); (non necessario); finalize() -> metodo dove definire azioni da eseguire con la distruzione di un oggetto, per rilasciare risorse diverse dalla memoria (non è un distruttore)!
Costruttori
Se non viene specificato, compilatore inserisce costruttore di default.
Si può invocare costruttore dentro un altro in questo modo: this(<param>); ma nella stessa classe.
Array
Dato tipo MyArray, un array di questo tipo è definito MyArray[] a; esistono anche array multidimensionali: MyArray [][] ma;
- Se non inizializzato, dichiarazione di array non alloca spazio per i suoi elementi.
- Allocazione dinamica tramite operatore new <tipo> [<dim>] : int[] i = new int[10];
- Se elementi non sono di un tipo primitivo, new alloca solo lo spazio per i riferimenti.
Person[] persona; //definita solo la variabile persona -> array non esiste ancora
persona = new Person[20]; //array creato, ma i diversi oggetti Person non esistono ancora
persona[0]=new Person(); //un oggetto di tipo Person creato con riferimento in posizione 0
NB: se creo array di float, alloca spazio per float.
Se creo array di Person, alloca spazio per riferimenti a oggetti di tipo Person (non alloca spazio per gli oggetti, ma per i riferimenti agli oggetti!!)
Copiare array
- Copia length elementi dell’array src, a partire dall’elemento con indice src_position, nell’array dst, a partire dall’elemento con indice dst_position.
Crescere un array
Assert -> serve a confermare se condizione logica è vera in un certo punto del programma.
- Serve a rilevare bug/errori.
- Per usare asserzioni bisogna abilitare usando java -ea Pila.
Nell’esempio si verifica che marker sia maggiore di 0.
Equivale a:
System serve da libreria globale (non è un oggetto):
- System.out.println(…); //per stampare
- System.gc(); //per attivare garbage collector
- System.exit(int status); //termina esecuzione del programma specificando codice di stato per indicare motivo della terminazione
- System.arraycopy(…); //per copiare array
- long System.currentTimeMillis(); //usato per misurare tempo corrente
Metodi e attributi di classe
Un attributo di una classe è condiviso da tutti gli oggetti della classe => le modifiche fatte con un’istanza sono visibili anche alle altre: b.y = 7 (non 2, perché x viene modificato nella riga prima ed è static)
Si può accedere a un attributo di classe senza bisogno di creare un oggetto tramite notazione <classe>.<attributo>
Metodo può essere invocato senza bisogno di creare oggetto tramite la notazione: <classe>.<metodo>(<par.attuali>)
Static
Static: (main lo è sempre)
- Da istanza posso accedere sia a metodi convenzionali sia static.
- Dalla classe posso accedere solo a metodi static.
- Un metodo static può accedere solo agli attributi e metodi static.
- Posso accedere a metodi static senza creare istanza: es: Shape.setScreen(…);
- Metodo convenzionale può accedere a metodi e attributi static.
- Blocco static viene eseguito una volta sola (es: public static void main(String[] args))
Final
Final: definisce attributi costanti.
final <definizione di attributo> = <valore>
static e final si possono usare insieme per de