Lezioni del corso di Metodologie di Programmazione (Canale A-L)
-
Lezione 1. Argomenti: Introduzione al corso. Il paradigma Object Oriented. Java e gli ambienti di sviluppo. Un semplice programma in Java (la divisione intera).
-
Lezione 2. Argomenti: Le classi viste come tipi di dato astratto (ADT). L'incapsulamento della struttura. L'ADT più semplice del mondo: le variabili. I costruttori. Prima l'inizializzazione o prima il costruttore? Un ADT più interessante: le pile (stack). Una implementazione rudimentale delle pile mediante array.
- Lezione 3. Argomenti: Pop da una lista vuota, push in una lista piena: le eccezioni. Try, catch, finally. Implementazione delle pile con eccezioni (parte prima). Le eccezioni trasportano informazioni: il parametro della clausola catch. Implementazione delle pile con eccezioni (parte seconda).
- Lezione 4. Argomenti: implementare stack di capacità illimitata. Usiamo le liste! Implementazione rudimentale delle liste. Implementazione delle pile usando le liste. Concatenazione di due liste. Creazione di una lista circolare: la pseudo-variabile this.
- Lezione 5. Argomenti: Sottoclassi. L'ereditarietà. Overloading e overriding. La pseudovariabile super. La risoluzione dei metodi è dinamica, quella degli attributi è statica.
- Lezione 6. Argomenti: Package. I modificatori di accesso: private vs. protected. Uso di this e super per invocare i costruttori. La risoluzione di this è dinamica, quella di super è statica.
- Lezione 7. Argomenti: Prendere i dati dal parametro args del main. Classi astratte. Interfacce. Le interfacce non sono classi completamente astratte.
- Prendere dati dall'array args
- Classi astratte
- Interfacce
- Lezione 8. Argomenti: il modificatore static. Accesso package restricted (ovvero quando manca il modificatore d'accesso); differenza con public. Scrivere programmi che usano tipi interfaccia, ovvero non fanno riferimento all'implementazione. Esempio: invertire uno stack. Le eccezioni sono parte del contratto, e dunque vanno dichiarate nell'interfaccia: la push di un ArrayStack può lanciare FullStackException, quella di ListStack no.
Anche le interfacce possono avere: attibuti (che sono implicitamente static), metodi statici, e metodi default, ovvero metodi non statici ereditati da tutte le classi che le implementano. Ereditarietà multipla?
- Static
- Figli. Si chiamano col loro numero d'ordine; ad ogni nuovo figlio che nasce, viene incrementato un contatore globale, membro statico della classe.
- Test figli.
- Il modificatore di accesso default (package)
- Classe dei vertebrati. L'attributo vertebre e' public; l'attributo vola e' package restricted.
- Classe dei tonni (+ main). Risiede nello stesso package dei vertebrati; il main crea due tonni (di cui uno volante) e accede all'attributo vola.
- Classe dei gatti (+ main). Risiede in un altro package e non ha accesso all'attributo vola.
- Interfacce (parte seconda)
- L'interfaccia degli stack
- Reverse (main). Inverte l'ordine degli elementi di uno stack. Funziona sia sugli stack fatti a lista che su quelli fatti con gli array.
- Metodi delle interfacce: statici e default. Come per le classi, nei metodi statici non si può far riferimento a membri non statici (non esiste un this), nei metodi default sì!
- Interuno. Una semplice interfaccia con un metodo default stampa.
- Interdue. Un'altra interfaccia dichiara un identico metodo default stampa.
- Risoluzione di metodi default. Una classe che implementa entrambe le interfacce. Dato che queste non sono in rapporto gerarchico fra loro, si ha un errore in compilazione (Java non supporta l'ereditarietà multipla). Una possibile soluzione: la classe fa l'overriding del metodo stampa.
- Lezione 9. Argomenti: Classi annidate, statiche e non. L'outer object. Come invocare il costruttore di una classe annidata. Classi locali a un metodo; visibilita' e accesso alle variabili locali.
- La classe degli stati. Ogni stato ha la sua (classe) Moneta.
- TestStati (main). Ogni stato ha riserve auree. Nascita della Svizzera. Piu' si coniano monete, piu' sale l'inflazione. Un franco svizzero puo' essere coniato anche fuori dalla svizzera (nel main).
- TestLocal (main). Blocchi e variabili locali. Classi locali... sono appunto locali! Hanno accesso solo a variabli final (Huh?!).
- Lezione 10. Argomenti: classi e metodi generici (introduzione). Input interattivo (scanner e input stream).
- IntList, le solite liste di int.
- GenericList, identica a IntList, ma astraendo rispetto al tipo int.
- TestListe (main), gioca con le liste.
- L'identità generica, metodo generico. Si trova in una classe non generica; ovviamente la classe che contiene un metodo generico può essere a sua volta generica, con parametri diversi da quelli del metodo. Include un main per test.
- Due istanze di sequenza (main). La classe generica LinkedList. Due istanze diverse. L'interfacia Iterable e i cicli for-each. L'input interattivo usando uno Scanner.
- Lezione 11. Argomenti: gerarchia di classi generiche. Per compatibilità con versioni di Java precedente alla 5, si possono creare oggetti di una classe generica senza istanziare il parametro formale di tipo (raw types). Non è preservata la gerarchia sui tipi argomento di una classe generica. La wildcard ("?"). Un tipo generico con wildcard è supertipo di tutte le sue istanze, ma non se ne possono creare oggetti. Vincoli sulla wildcard: extends e super.
- Lezione 12. Argomenti: Classi anonime. Due modi per crearle: estendendo una classe o implementando un'interfaccia.
- Lezione 13. Argomenti: Lambda espressioni. Definiscono anch'esse classi anomime. Inferenza dei tipi.
- Lezione 14. Argomenti: Thread. Introduzione.
- Stampatore. Estende Thread, ridefinendo il metodo run(). Stampa e termina.
- NarcoStampatore. Dorme, stampa e termina. Nota: il metodo sleep() lancia un'eccezione se il thread e' interrotto.
- Test (main). Testa 6 thread.
- Stampatore compulsivo. Dorme e stampa in un ciclo infinito. Se interrotto usa getName().
- Gioca a Snapo-snapo-raz (main). Lancia due compulsivi, cui da' un nome, setName(String). Li interrompe dopo 5K millisecondi.
- Lezione 15. Argomenti: La sincronizzazione dei thread. Motivazioni: esempio di due thread consumatori che condividono uno stack. Il deadlock
- ArrayStack. La pop() e'/non e' sincronizzata.
- Popper. Thread consumatore.
- Test1 (main). Crea uno stack e lancia due consumatori. Senza sincronizzazione si perde un elemento.
- DeadManWalking (thread votati alla morte). Eseguono due sincronizzazioni annidate.
- DeadLock (main). Lancia due DeadManWalking passandogli gli stessi monitor, ma in ordine inverso: deadlock! (Vedi anche la prova scritta di settembre 2019.)
- Lezione 16. Argomenti: Wait(), notify() e notifyAll(). Esempio di implementazione di uno stack in regime di concorrenza. I metodi wait, notify e notifyAll possono essere invocati esclusivamente all'interno di codice sincronizzato, utilizzando il lock dell'oggetto sul quale vengono invocati.
- Lezione 17. Argomenti: Creare un thread usando runnable. Come fermare un thread. Sincronizzazione con variabili volatile.
- JimKongOn (thread). Viene fermato col meccanismo dell'interrupt.
- RonaldDrump (runnable). Viene fermato con l'interrupt, ma non si puo' usare this.isInterrupted().
- EnricoBossi (runnable). Ha un suo metodo fermati() che opera su una variabile volatile.
- BadBoys (main).
- Lezione 18. Argomenti: Come far incontrare uomini e donne? (...caso studio orientato al progetto 2017.) Random.
- MyListElem. I soliti elementi di linked list.
- SynchroCoda. Solita implementazione delle code in ambiente concorrente, con wait() e notifyAll()
- Ballo. Un luogo di incontro, tutto static.
- Bullo (thread). Si mettono in attesa sulla coda delle pupe.
- Pupa (thread). Si mettono in attesa su se stesse.
- Bulli e Pupe (main). Frank, Marlon, Anastasia e Genoveffa al ballo
- Lezione 19. Argomenti: Reflection (parte prima). Class, Member, Constructor, Method.
- HuskyDog. Una classe di Husky. Sanno mangiare polli e scappare.
- TestReflection (main). Viene creato un oggetto di tipo Class e viene usato per costruire oggetti della classe corrispondente e invocarne metodi. Class e' un tipo generico!
- Lezione 20. Argomenti: Reflection (parte seconda).
- Annotazioni.
- ArrayConsistency. Un tipo annotazione.
- ArrayStack. La solita implementazione degli Stack con array. Include un'annotazione di tipo ArrayConsistency: il puntatore a top deve essere complreso nei limiti dell'array.
- Annotated ArrayStack (estensione banale di ArrayStack). Mostra un'annotazione nativa di IntelliJ: Override.
- Violazione (main). Reflection e violazione di private/protected. Manomissione degli stack usando setAccessible.
- Motivazioni per l'uso la reflection. Programmazione di ambienti di plug-in. Spostare a runtime controlli del compilatore.
- Agente (interfaccia).
- MyAgente (implementazione di Agente).
- TestAgente (main). Supponiamo di voler scrivere un main per testare un homework dove si chiede di implementare l'interfaccia Agente...
- Lezione 21. Argomenti: Assert. Il metodo delle invarianti. Throwable: errori vs. eccezioni.
- Aegyptian. Moltiplicazione egiziana (a * b). Attraverso le asserzioni possiamo intercettare errori "untrapped": l'algoritmo non funziona se b<0, ma potremmo non accorgercene...
- Lezione 22. Argomenti: programmazione funzionale in Java
- TestFunction (main). Uso dell'interfaccia (funzionale) Function, che include metodi default generici che implementano la composizione.
- Funtori
- Correctness. Un tipo annotazione.
- Functor. Interfaccia funzionale generica. Il metodo astratto fmap mappa funzioni f:A->B in funzioni Functor(f): Functor(A) -> Functor(B). Include una annotazione di correttezza: fmap deve preservare la composizione di funzioni.
- Il funtore delle liste (classe generica, implementa Functor). Tipica implementazione delle liste di puntatori (con val e next), alla quale si aggiunge l'operazione fmap del funtore che data f:A -> B restituisce l'ovvia funzione da liste di A in liste di B.
- FunctorTest (main). Usando fmap ottiene da una lista linkata di interi la corrispondente lista di booleani in cui true corrisponde a pari e false a dispari.
- Monadi
- L'interfaccia (funzionale) Monad delle monadi (o quasi). Analoga a quella dei funtori.
- La monade dei valori con tempo computazionale (un intero). La composizione (monadica) di due funzioni somma automaticamente i tempi computazionali di ciascuna. Nota: sorge un problema se vogliamo che implementi l'interfaccia Monad.
- MonadTest (main). Compone tre funzioni della forma A -> Monad(B).
- La monade Optional (main). Un esempio di monade in java.util (altro esempio sono gli stream). Nella teoria delle categorie, of e flatMap si chiamano rispettivamente unit e lifting di Kleisli.