Estratto del documento

Programmazione III

Dispense

Java: eventi e GUI, pattern Observer e MVC, JavaFX,

programmazione concorrente e socket

Programmazione III · Dispense Indice

1. Architetture software 5

1.1 Modello a oggetti e UML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.2 Dai monoliti alle architetture n-tier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2. Java: compilazione e memoria 6

2.1 Dal sorgente all'esecuzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.2 Memoria della JVM e passaggio dei parametri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

3. Ereditarietà, polimorfismo, interfacce 7

3.1 Sottoclassi e sottotipi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3.2 Tipo statico, tipo dinamico, upcasting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3.3 Overriding e super . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3.4 Binding dinamico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3.5 Downcasting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3.6 Classi astratte e interfacce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3.7 Lo schema Kernel–Modulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

4. RTTI e Reflection 10

4.1 instanceof o getClass()? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

4.2 Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

5. Input/Output 11

5.1 Stream, byte e caratteri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

5.2 Composizione di stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

5.3 Eccezioni e chiusura delle risorse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

5.4 Scanner e PrintWriter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

5.5 Serializzazione di oggetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

6. Generici e collezioni 13

6.1 Tipi generici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

6.2 Type erasure e raw type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

6.3 Collezioni e iteratori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

6.4 Generici, sottotipi e wildcard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

7. Classi innestate e lambda expression 15

7.1 Tipi innestati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

7.2 Classi anonime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

7.3 Lambda expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

8. Eventi e interfacce grafiche con Swing 17

8.1 Programmazione guidata dagli eventi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

8.2 Swing in breve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

8.3 Il modello a delega: sorgenti, eventi, listener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

8.4 Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

2

Programmazione III · Dispense

8.5 Schemi di uso dei listener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

8.6 Generare eventi personalizzati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

9. Pattern Observer–Observable 20

9.1 L'API di java.util . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

9.2 Variante senza java.util.Observable (non nelle slide) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

10. Pattern MVC 22

10.1 Senza Observer: tutto è accoppiato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

10.2 Con Observer: il modello notifica le viste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

10.3 Un ulteriore miglioramento: interfaccia per la vista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

11. JavaFX 24

11.1 Struttura di un'applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

11.2 Fogli stile CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

11.3 MVC con FXML: il modo di lavorare del corso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

11.4 JavaBeans e properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

11.5 Binding di properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

11.6 Collezioni osservabili e più viste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

12. Thread 27

12.1 Creare e avviare un thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

12.2 Ciclo di vita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

12.3 Controllo dei thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

12.4 Eccezioni nei thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

12.5 Thread e interfacce grafiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

13. Sincronizzazione e cooperazione 29

13.1 Interferenza e sezioni critiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

13.2 Semaphore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

13.3 synchronized . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

13.4 Cooperazione: wait e notify . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

13.5 Deadlock e starvation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

13.6 Attenzione alla granularità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

14. Il package java.util.concurrent 32

14.1 BlockingQueue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

14.2 Lock, ReentrantLock e Condition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

14.3 ReadWriteLock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

15. Pipe 34

16. Task, thread pool, Callable e Future 35

16.1 Executor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

16.2 Callable e Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

16.3 ScheduledExecutorService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

17. Socket 36

3

Programmazione III · Dispense

17.1 Servire più client in parallelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

17.2 Stream di oggetti sui socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

18. Errori tipici (da rivedere prima dell'esame) 38

4

Programmazione III · Dispense 1. Architetture software

Il corso non tratta i microservizi (li affronta TAAS in magistrale), ma insegna a strutturare le applicazioni a

componenti, anche quando poi girano tutte in una sola JVM. I vantaggi sono modularità, riuso, manutenibilità,

separation of concerns e information hiding; inoltre ci si abitua a ragionare su quali componenti lavorano in

parallelo e quali dati condividono, che è il tema dei capitoli sui thread.

1.1 Modello a oggetti e UML

L'approccio Object Oriented usa lo stesso modello in tutte le fasi: analisi (OOA), progetto (OOD) e

programmazione (OOP). Il class diagram UML è il modello OOA dell'applicazione: contiene solo gli oggetti del

dominio del problema, con le loro strutture dati e operazioni, ed è indipendente da linguaggio, interfaccia utente e

database.

1.2 Dai monoliti alle architetture n-tier

Architettura Com'è fatta Pregi e limiti

Un unico blocco di codice con interfaccia, logica e Nessuna separazione; applicazioni

Monolite gestione dei dati. Tipico dei mainframe. stand-alone.

Client/server Backend (server) con database e manipolazione dei Più scalabile (carico sui client). Ma la

dati; frontend (client) con l'interfaccia. Diffusa dalla business logic è spezzata tra client e server:

(two-tier) è difficile riusare la UI con dati diversi o lo

fine degli anni '70. stesso DB da frontend diversi.

Livello 1: dati (DBMS, XML...). Livello 2: business

Three-tier Nessun livello fa assunzioni

logic. Livello 3: interfaccia utente. Dai primi anni '90. sull'implementazione degli altri: ognuno

conosce solo come comunicare con quelli

adiacenti.

UI, presentation logic, business logic, infrastructure

n-tier Permette configurazioni diverse.

services (messaggistica, transazioni), data layer.

Vantaggi del three-tier: flessibilità (le componenti sono riusabili e modificarne una non impatta il resto, a meno di

cambi di API; i bug si cercano in modo mirato), interconnettività (N interfacce diverse sullo stesso servizio, più

applicazioni sugli stessi dati) e gestione di sistemi distribuiti (si aggiorna la logica senza toccare i client).

Nota

Three-tier è un concetto logico, non fisico: i tre livelli possono stare su tre macchine, su due o anche su una sola.

Sul piano della comunicazione tra servizi si distingue tra interazione sincrona request/response (orchestration) e

asincrona basata su eventi (choreography), tipicamente tramite un message broker (es. RabbitMQ, protocollo

AMQP). L'idea di base, componenti che non si conoscono ma si scambiano messaggi, ritorna nei listener e nel

pattern Observer. 5

Programmazione III · Dispense 2. Java: compilazione e memoria

2.1 Dal sorgente all'esecuzione

Il compilatore trasforma in bytecode ( ), eseguito da una macchina virtuale (la

MyClass.java MyClass.class

JVM) su sistemi diversi. Il garbage collector libera in background la memoria degli oggetti non più raggiungibili.

2.2 Memoria della JVM e passaggio dei parametri

La memoria è divisa in tre aree:

• memoria statica: codice delle classi, costanti e variabili (una sola copia per classe);

static

• stack: un record di attivazione (frame) per ogni invocazione di metodo, con parametri formali, variabili locali,

valore e indirizzo di ritorno. Esiste solo finché il metodo è in esecuzione;

• heap: gli oggetti creati con e gli array. Le variabili di istanza vivono qui, una copia per oggetto.

new

Il passaggio di parametri è sempre per valore. Per gli oggetti si copia il riferimento: il metodo può modificare

l'oggetto puntato (es. riempire un array ricevuto) ma non riassegnare la variabile del chiamante. Non esistono ref

e .

out

Da ricordare

Quando arriveremo ai thread: ogni thread ha il proprio stack, mentre l'heap è condiviso. È la ragione per cui

due thread possono interferire sugli stessi oggetti (cap. 12-13).

6

Programmazione III · Dispense

3. Ereditarietà, polimorfismo, interfacce

3.1 Sottoclassi e sottotipi crea una sottoclasse che eredita variabili e metodi di istanza della

class WindowWithTitle extends MyWindow

sopraclasse e può aggiungerne o ridefinirne. L'ereditarietà realizza la relazione is-a: un rettangolo è un poligono.

In Java l'ereditarietà è singola (albero con radice ; i tipi primitivi non sono ); l'ereditarietà multipla è

Object Object

sostituita dalle interfacce.

3.2 Tipo statico, tipo dinamico, upcasting

Il type checking statico lo fa il compilatore, guardando i tipi dichiarati. Il tipo reale di un oggetto si conosce solo a

runtime. Il polimorfismo è la proprietà di un oggetto di avere più tipi lungo la gerarchia: l'assegnamento x = expr

è legale se il tipo di è uguale a quello di o ne è un sottotipo. Spostarsi verso un supertipo (upcasting) è

expr x

sempre sicuro, perché la sottoclasse ha tutti i metodi della sopraclasse.

MyPolygon p = new MyRectangle(); // upcasting

p.draw(); // ok: draw() esiste in MyPolygon

p.diagonal(); // ERRORE di compilazione: il tipo dichiarato non ha diagonal()

((MyRectangle) p).diagonal(); // ok con un downcast (verificato a runtime)

3.3 Overriding e super

Una sottoclasse può ridefinire (override) un metodo; con ne riusa la versione della sopraclasse

super.metodo()

per estenderla invece di sostituirla, e con invoca il costruttore. I campi non sono accessibili

super(...) private

alla sottoclasse: si passa dai metodi pubblici.

class Cell {

private int content = 0;

public int get() { return content; }

public void set(int n) { content = n; }

}

class CellWithMemory extends Cell {

private int backup = 0;

@Override public void set(int n) { backup = get(); super.set(n); }

public void restore() { super.set(backup); }

}

3.4 Binding dinamico

Nei linguaggi a oggetti la chiamata di un metodo è risolta a runtime in base al tipo reale dell'oggetto. Vale solo

per i metodi: l'accesso ai campi è risolto staticamente dal tipo dichiarato, e un campo con lo stesso nome in una

sottoclasse nasconde quello della sopraclasse senza ridefinirlo.

class A {

String type = "A";

String getType() { return type; }

void printViaMethod() { System.out.println(getType()); }

void printViaField() { System.out.println(type); }

}

class B extends A {

String type = "B";

@Override String getType() { return type; }

}

B b = new B();

b.printViaMethod(); // B : getType() è dinamico, esegue la versione di B

b.printViaField(); // A : il campo è risolto in A, dove è scritto il codice

System.out.println(b.type); // B

Il binding dinamico sostituisce gli sul tipo: invece di una procedura che considera ogni forma, si ridefinisce

switch

in ogni sottoclasse e il codice chiamante resta immutato quando si aggiunge una forma.

draw() 7

Programmazione III · Dispense

abstract class MyShape { abstract void draw(); }

class MyRectangle extends MyShape { void draw() { /* ... */ } }

class Figure {

MyShape[] shapes;

void drawFigure() { for (MyShape s : shapes) s.draw(); } // aggiungere MyTriangle non cambia Figure

}

3.5 Downcasting

Il downcast va da un tipo generale a uno specifico: . Il compilatore lo accetta se è plausibile; a runtime la

(C) obj

JVM verifica che l'oggetto sia davvero un (o un suo sottotipo) e altrimenti lancia . Con

C ClassCastException

classi e interfacce il compilatore è più permissivo: accetta il cast se esiste un possibile sottotipo comune ai due

tipi. Per prevenire l'eccezione si verifica prima il tipo, senza abusarne (spesso il polimorfismo evita il cast).

Shape f = ...;

if (f instanceof Circle) { Circle c = (Circle) f; c.op(); }

3.6 Classi astratte e interfacce

Una classe astratta ha almeno un metodo (senza corpo): può avere costruttore, campi e metodi

abstract

concreti ma non si può istanziare con . Un'interfaccia contiene solo la firma dei metodi, cioè un contratto, e

new

non è vincolata alla struttura ad albero.

Classe astratta Interfaccia

extends implements A, B

Ereditarietà una sola ( ) quante si vuole ( )

Contenuto campi, costruttori, metodi concreti e astratti firme dei metodi (il contratto)

contratto implementabile da classi di gerarchie

Quando base comune con codice condiviso diverse

Un oggetto visto tramite un'interfaccia mostra solo i metodi di quell'interfaccia ( non permette

A a = new C();

, a meno di un downcast ). Un esempio di libreria è , che permette a

a.metodB() ((C) a).metodB() Comparable

di ordinare qualunque classe implementi :

Arrays.sort compareTo

class MyRectangle extends MyPolygon implements Comparable<MyRectangle> {

int height, width;

public int compareTo(MyRectangle r) { return height - r.height; }

}

MyRectangle[] a = new MyRectangle[10];

Arrays.sort(a); // ordina usando compareTo() degli elementi

3.7 Lo schema Kernel–Modulo

Combinando interfacce, classi che le implementano e relazioni di contenimento si ottiene lo schema alla base dei

pattern architetturali del corso. Una classe kernel usa un componente di tipo interfaccia modulo (in upcasting) e

ne invoca i metodi; le implementazioni del modulo sono scritte a parte. Grazie a polimorfismo e binding

Anteprima
Vedrai una selezione di 9 pagine su 38
Appunti di Programmazione III Pag. 1 Appunti di Programmazione III Pag. 2
Anteprima di 9 pagg. su 38.
Scarica il documento per vederlo tutto.
Appunti di Programmazione III Pag. 6
Anteprima di 9 pagg. su 38.
Scarica il documento per vederlo tutto.
Appunti di Programmazione III Pag. 11
Anteprima di 9 pagg. su 38.
Scarica il documento per vederlo tutto.
Appunti di Programmazione III Pag. 16
Anteprima di 9 pagg. su 38.
Scarica il documento per vederlo tutto.
Appunti di Programmazione III Pag. 21
Anteprima di 9 pagg. su 38.
Scarica il documento per vederlo tutto.
Appunti di Programmazione III Pag. 26
Anteprima di 9 pagg. su 38.
Scarica il documento per vederlo tutto.
Appunti di Programmazione III Pag. 31
Anteprima di 9 pagg. su 38.
Scarica il documento per vederlo tutto.
Appunti di Programmazione III Pag. 36
1 su 38
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher maurizio.costa.03 di informazioni apprese con la frequenza delle lezioni di Programmazione III e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli studi di Torino o del prof Capecchi Sara.

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community