• Non ci sono risultati.

Introduzione a Java. March 23, Livio Tenze

N/A
N/A
Protected

Academic year: 2022

Condividi "Introduzione a Java. March 23, Livio Tenze"

Copied!
124
0
0

Testo completo

(1)

Introduzione a Java

Livio Tenze ltenze@units.it

March 23, 2021

(2)

Prima di iniziare

Cosa bisogna installare:

https://www.jetbrains.com/idea/download

Oracle JDK http://www.oracle.com/technetwork/java/

javase/downloads/index.html

(3)

Paradigmi di programmazione

Esistono due differenti modi per descrivere il mondo Come un sistema di processi (modello procedurale)

Tipicamente descritto con flow-chart Usa procedure, funzioni, strutture Cobol, Fortran, Basic, Pascal, C

Come un sistema di cose (modello a oggetti)

Tipicamente descritto come gerarchie e dipendenze tra classi Usa dichiarazioni di classi e di metodi

Simula, Smalltalk, Eiffel, C++, Java

(4)

Cosa ` e Java

Linguaggio definito dalla Sun Microsystems (1991), acquisito dalla Oracle

Si voleva estendere il linguaggio C++

La prima versione del linguaggio si chiam`o Oak, poi Java (1995)

Non doveva essere legato ad un processore o una piattaforma (bytecodes)

Permette lo sviluppo di applicazioni su piattaforme multiple, in reti eterogenee e distribuite (Internet)

Esistono pi`u compilatori Java e Virtual Machines Oracle

OpenJDK IBM

Blackdown (porting Linux di SunSoft), ora OpenJDK

(5)

Introduzione a Java

Java `e un linguaggio object-oriented, con alcune caratteristiche:

fortemente tipizzato: ogni espressione ha un tipo, che il compilatore usa per controllare la correttezza delle operazioni eseguite

tutti gli errori sono rilevati al momento in cui avvengono, non sono possibili errori non catturati (unchecked error)

non `e consentito l’accesso diretto alla memoria

gestione automatica della memoria a heap, con garbage collector: la deallocazione non `e gestita dal programmatore, ma `e il supporto a run time che si occupa di liberare la memoria non pi`u usata

Dynamic loading and linking: le classi vengono caricate solo al momento del loro effettivo utilizzo

(6)

Alcuni aspetti della JDK

JDK - Java development kit, arrivata alla versione 15

Il caricamento delle classi viene gestito mediante la variabile CLASSPATH: contiene una serie di stringhe suddivise da “;”

o “:” che rappresentano il nome completo di un archivio di classi (jar o zip) o di directory contenti file con estensione .class.

Compilatore java: javac

export CLASSPATH=/home/user/classes.zip javac pippo.java

E possibile usare l’opzione -classpath nella chiamata di javac` Debugger java (compilare con opzione -g): jdb

javac -g pippo.java jdb pippo

(7)

Alcuni aspetti della JDK

Interprete java: java

java pippo <arg1> <arg2> ...

Editor

Programma pippo.java

Compilatore

bytecode pippo.class

Loader

Carica il byte- code in memoria

Bytecode verifier Verifica che il bytecode non violi le re- strizioni di Java

Interprete

Legge il byte- code e lo esegue

(8)

Variabili

Una serie di primitive per poter creare strutture pi`u complesse.

Primitiva Dimensione Val. minimo Val. massimo

boolean 1-bit - -

char 16-bit Unicode 0 Unicode 216− 1

byte 8-bit -128 127

short 16-bit −215 215− 1

int 32-bit −231 231− 1

long 64-bit −263 263− 1

float 32-bit IEEE754 IEEE754

double 64-bit IEEE754 IEEE754

void - - -

Le variabili devono iniziare con una lettera, possono contenere numeri: identificatore var name;

(9)

Inizializzazione variabile

`E buona norma inizializzare la variabile una volta dichiarata:

identificatore var name = var value;

int p r i m o i n t e r o = 1 0 0 ;

Java, in ogni caso assegna ad ogni variabile un valore di default al momento della dichiarazione.

Tipo primitivo Valore assegnato

boolean false

char \u0000

byte 0

short 0

int 0

long 0L

float 0x0f

double 0.0

(10)

Variabili final

A differenza di molti altri linguaggi, Java non consente di definire costanti. Per far fronte alla mancanza `e possibile utilizzare il modificatore final. Una variabile dichiarata final si comporta come una costante, pertanto le deve essere assegnato il valore iniziale al momento della sua dichiarazione utilizzando l’operatore “=” di assegnazione.

f i n a l int p i p p o = 10;

(11)

Operatori

Operatori Funzioni

++ - - + - aritmetiche unarie e booleane

* / % aritmetiche

+ - addizione, sottrazione e concatenazione

<< >> >>> shift bit

< <= > >= instanceof comparazione (relazionali)

== != Uguaglianza e disuguaglianza (relazionali)

&ˆ| bit AND, XOR e OR

&& || ! logico AND, OR e NOT expr ? expr : expr Condizione a tre

Tutti gli operatori funzionano solamente con dati primitivi a parte gli operatori !=, == e = che hanno effetto anche se gli operandi sono rappresentati da oggetti. Inoltre la classe String utilizza gli

(12)

Esempio1

Esempio operatori appena visti, chiamate di java/javac.

(13)

Classi

Classe: descrizione astratta dei dati relativi a un concetto (attributi) e dei comportamenti tipici relativi

(metodi/funzioni)

Oggetto: istanza di una classe

Comunicazione attraverso messaggi (invocazione) Un oggetto `e una coppia (stato, funzioni)

Esempio

Automobile `e una classe (rappresenta il concetto generico di automobile)

Fiat Brava `e una classe (rappresenta il concetto di un tipo di automobile)

L’oggetto targato AX 266 WS `e un’istanza di Fiat Brava

(14)

Classi

Chiariamo

Oggetto: istanza (esemplare) di una classe Creazione di un oggetto: ISTANZIAZIONE

Due istanze della stessa classe NON sono lo stesso oggetto Due istanze diverse hanno la stessa INTERFACCIA

p u b l i c c l a s s A u t o m o b i l e {

p r i v a t e int l i t r i S e r b a t o i o = 50; /* a t t r i b u t i */

/* m e t o d i */

p u b l i c v o i d a v v i a t i (){ /* i m p l e m e n t a z i o n e */ };

/* s t a r t p o i n t */

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g v ) { A u t o m o b i l e a = new A u t o m o b i l e ();

a . a v v i a t i ();

}

(15)

Cosa sono le reference

Java fa una netta distinzione tra Classi e tipi primitivi.

int c o u n t e r ;

Questa dichiarazione crea una variabile intera chiamata counter ed alloca subito quattro byte per lo “storage” del dato.

S t a c k s ;

crea una variabile che referenzia l’oggetto, ma non crea l’oggetto Stack. Una variabile di referenza, `e quindi una variabile speciale che tiene traccia di istanze di tipi non primitivi.

N.B.: una referenza ad un oggetto di tipo Stack non pu`o tracciare oggetti di diverso tipo.

Un discorso simile vale anche per gli array:

int[] n u m b e r s ; /* r e f e r e n c e */

(16)

Considerazioni sulle variabili

Allocazione delle variabili

A differenza di C e C++ in cui un dato rappresenta il

corrispondente dato-macchina ossia una variabile intera in C++

occupa 32 bit ed una variabile byte ne occupa 8, ora le variabili si

“comportano come se”.

La virtual machine Java difatti alloca per ogni dato primitivo il massimo disponibile in fatto di rappresentazione macchina dei dati.

La virtual machine riserver`a, su una macchina a 32 bit, 32 bit sia per variabili intere che variabili byte, quello che cambia `e che il programmatore vedr`a una variabile byte comportarsi come tale ed altrettanto per le altre primitive.

(17)

Blocchi

Un blocco `e una porzione di codice racchiusa tra graffe

{ // b l o c c o ...

}

La visibilit`a del nome di una variabile indica le parti di un programma in cui il nome pu`o essere utilizzato per riferirsi alla variabile.

Una variabile dichiarata all’interno di un blocco

`

e visibile solo all’interno del blocco stesso, e dei sottoblocchi

`

e visibile solo dal punto della dichiarazione in poi Vincoli (controllati staticamente dal compilatore)

ogni variabile deve essere inizializzata prima del suo utilizzo

(18)

Scope dei dati

`E possibile dichiarare variabili con lo stesso nome, la visibilit`a delle variabili dipende dal blocco di istruzioni in cui essa `e dichiarata.

Si dice che una variabile ha scope limitato al blocco in cui `e dichiarata.

c l a s s O b j e c t N a m e { d a t a _ d e c l a r a t i o n s m e t h o d _ d e c l a r a t i o n s }

Scope variabili in una dichiarazione di metodo:

r e t u r n _ t y p e m e t h o d _ n a m e ( a r g _ t y p e n a m e [ , a r g _ t y p e n a m e ]) {

int i = 0;

{

f l o a t j = 5 . 0 ; }

}

(19)

Oggetto null

null

Il linguaggio Java prevede un valore speciale per le variabili reference che non referenzia nessuna istanza di un oggetto. Il valore speciale null rappresenta un oggetto inesistente, e viene assegnato di default ad ogni variabile reference.

Garbage collector

Quando ad una variabile reference viene assegnato il valore null, l’oggetto referenziato verr`a rilasciato e, se non utilizzato verr`a dato in pasto al garbage collector che si occuper`a di rilasciare la

memoria allocata per la entit`a.

S t a c k s = n u l l; int[] n u m b e r s ;

if ( n u m b e r s == n u l l) { /* t h e n */ }

(20)

Creazione di istanze

Creata la variabile reference, siamo pronti a creare una istanza di un nuovo oggetto o di un array. L’operatore new fa questo per noi, allocando la memoria necessaria per il nostro oggetto e tornando la locazione in memoria della entit`a creata.

Si usa l’operatore new:

S t a c k s = new S t a c k ();

Anche gli array vengono allocati nello stesso modo:

int[] m y _ a r r a y = new int[ 2 0 ] ;

(21)

Operatore .

Definizione

Questo operatore `e utilizzato per accedere ai membri di un oggetto tramite la variabile reference.

c l a s s S t a c k E l e m e n t { int val ;

}

c l a s s S t a c k {

S t a c k E l e m e n t pop () { ...

}

v o i d p u s h ( S t a c k E l e m e n t ele ) { ...

} }

(22)

Operatore .

Creiamo l’oggetto ed accediamo ai metodi e attributi:

S t a c k E l e m e n t s _ e l e = new S t a c k E l e m e n t ();

int v a l u e = 10;

s _ e l e . val = v a l u e ;

S t a c k s = new S t a c k ();

s . p u s h ( s _ e l e );

// R i l a s c i a m o s _ e l e e r e c u p e r i a m o il v a l o r e // d a l l o s t a c k

s _ e l e = n u l l; s _ e l e = s . pop ();

(23)

this

A cosa serve this

Java prevede una modalit`a di referenziazione speciale identificata da this. Difatti il valore di this viene modificato automaticamente da Java in modo che ad ogni istante sia sempre referenziato all’oggetto attivo.

c l a s s S t a c k E l e m e n t { int val ;

v o i d s e t V a l (int val ) { t h i s. val = val ; }

}

(24)

String

Java fornisce varie classi gi`a definite, una di queste `e String. Sono oggetti che possono essere facilmente creati, possono essere concatenati e fornire un controllo sulla lunghezza della stringa.

S t r i n g p r i m a = " h e l l o " ; S t r i n g s e c o n d a = " w o r l d " ;

S t r i n g t e r z a = p r i m a + s e c o n d a ; int l u n g h e z z a = p r i m a . l e n g t h ();

(25)

Comparazione di oggetti

Stato di un oggetto

Gli oggetti Java rappresentano dati molto complessi il cui stato, a differenza di un tipo primitivo, non pu`o essere definito

semplicemente dal valore della variabile reference. In particolare, definiamo stato di un oggetto il valore in un certo istante di tutti i dati membro della classe. Ad esempio lo stato dell’oggetto

StackElement `e rappresentato dal valore del dato membro val di tipo intero.

S t a c k a = new S t a c k ();

S t a c k b = new S t a c k ();

( a == b ) - > f a l s e!!

Ci`o che si confronta sopra `e il valore del reference e non lo stato dell’oggetto.

(26)

Comparazione di oggetti

Per confrontare correttamente i due oggetti visti prima `e necessario usare il metodo equals, che viene ereditato dalla classe Object.

a . p u s h ( 1 ) ; b . p u s h ( 1 ) ;

a . e q u a l s ( b ) - > t r u e

(27)

Metodi statici

Definizione

Metodi statici, ossia metodi che appartengono a classi, ma non richiedono oggetti attivi. Questi metodi possono essere creati utilizzando la parola chiave static a sinistra della dichiarazione

c l a s s e s e m p i o {

s t a t i c int m e t o d o _ s t a t i c o () { ...

} }

c l a s s a l t r a { v o i d m e t o d o () {

int i = e s e m p i o . m e t o d o _ s t a t i c o ();

} }

Per chiamare metodo statico non `e stato necessario istanziare

(28)

Metodi statici

Affinch´e la Java Virtual Machine possa eseguire una applicazione,

`e necessario che abbia ben chiaro quale debba essere il primo metodo da eseguire. Questo metodo viene detto entry point della applicazione.

c l a s s p r i m a _ a p p l i c a z i o n e {

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g v ) { ...

} }

Anche l’applicazione `e un oggetto!

(29)

Classe System

Un’altra delle classi predefinite in Java `e la classe System. Questa classe ha una serie di metodi statici. Due dei metodi statici contenuti nella classe sono System.out e System.err che rappresentano rispettivamente lo standard output e lo standard error dell’interprete java.

S y s t e m . out . p r i n t l n ( " S c r i v o s u l l o s t a n d a r d o u t p u t " );

S y s t e m . err . p r i n t l n ( " S c r i v o s u l l o s t a n d a r d e r r o r " );

S y s t e m . e x i t ( 0 ) ; // E s c o d a l l a a p p l i c a z i o n e

(30)

Esempio2

Uno Stack o Pila `e una struttura dati gestita secondo la filosofia LIFO (Last In First Out) ovvero l’ultimo elemento ad essere inserito `e il primo ad essere recuperato.

Disegnare e realizzare una classe Stack che contenga al massimo 20 numeri interi e deve avere i due metodi:

v o i d p u s h (int) int pop ()

(31)

Istruzioni per il controllo del flusso

Modificatori

condizionali: if – else, switch di ciclo: while, do – while, for di interruzione: break, continue di ritorno: return

gestione eccezioni: try - catch, finally

(32)

Condizionale if–then–else

if ( < c o n d i z i o n e >) {

< C1 >

} e l s e if ( < c o n d i z i o n e >) {

< C2 >

} e l s e {

< C3 >

}

Con condizione si intende indicare un’espressione booleana. I blocchi if-then-else possono presentarsi annidati.

(33)

Condizionale switch

s w i t c h ( < e s p r e s s i o n e >) { c a s e e s p r _ c o s t a n t e : ...

b r e a k;

c a s e e s p r _ c o s t a n t e : ...

b r e a k;

d e f a u l t:

...

}

Dove con espressione si indica ogni espressione valida che produca un intero.

(34)

Ciclo while e do–while

w h i l e ( < c o n d i z i o n e >) {

< corpo >

}

La condizione booleana viene valutata all’inizio del blocco di istruzioni.

do {

< corpo >

} w h i l e( < c o n d i z i o n e >);

La condizione viene valuta al termine del blocco di istruzioni.

(35)

Ciclo for

for ( i n i t _ s t a t e m e n t ; c o n d i t i o n a l _ e x p r ; i t e r a t i o n _ s t m t ) { i s t r u z i o n i

}

L’istruzione for, come in C e in C++, `e molto versatile in quanto consente di scrivere cicli di esecuzione utilizzando molte varianti alla forma descritta sopra. Ad esempio per creare un ciclo infinito si pu`o scrivere:

for ( ; ; ) {}

Oppure si possono complicare le espressioni di inizio, condizione ed incremento:

for (int i =0 , j = 0 ; ( i <10 && j > 0 ) ; i ++ , j ++) { ...

}

(36)

Istruzioni di ramificazione

Istruzioni

break interrompe l’esecuzione di un ciclo evitanto ogni controllo condizionale

continue salta un blocco di istruzioni all’interno del ciclo e torna il controllo all’espressione booleana

return interrompe l’esecuzione e torna in controllo al metodo chiamante

Esempio:

for (int i = 0 ; ; i ++) { if ( i = = 1 0 ) b r e a k; ...

}

(37)

continue e return

w h i l e( i < 2 0 ) { i ++;

if (( i % 2 ) ! = 0 ) c o n t i n u e; p a i r s ++

}

v o i d m e t o d o () {

for (int i =0; i < 1 0 ; i ++) { ...

if ( i = = 5 ) r e t u r n; }

}

Nel caso in cui il metodo non restituisse void, avremmo usato l’espressione return ret val.

(38)

Package java

Definizione

I package sono meccanismi per raggruppare definizioni di classe in librerie, similmente ad altri linguaggi di programmazione. Il meccanismo `e provvisto di una struttura gerarchica per

l’assegnamento di nomi alle classi in modo da evitare eventuali collisioni in caso in cui alcuni programmatori usino lo stesso nome per differenti definizioni di classe.

Benefici dall’uso dei package:

le classi possono essere mascherate all’interno dei package (incapsulamento nel file)

le classi possono condividere dati e metodi con classi di altri package

i package forniscono un meccanismo efficace per distribuire

(39)

Package in pratica

I package combinano definizioni di classi in un unico archivio la cui struttura gerarchica rispetta quella del file system. I nomi dei package sono separati tra loro da punto.

Se la pippo corporation avesse generato un insieme di classi dedicate al calcolo statistico, le classi dovrebbero essere contenute in un package chiamato ad esempio pippo.stat

Per archiviare una classe all’interno di un package `e necessario aggiungere l’istruzione

p a c k a g e p i p p o . s t a t ;

all’inizio del codice sorgente.

(40)

Package

Creazione del package

Una volta definito il nome di un package, deve essere creata su disco la struttura a directory che rappresenti la gerarchia definita dai nomi.

Per trovare le classi contenute in un package, Java utilizza la variabile di ambiente CLASSPATH che contiene le informazioni per puntare alla root del nome del package e non direttamente alle classi all’interno del package.

CLASSPATH = /java/lib/tools.jar;/java/import;.;./;

(41)

Modificatore public

Comportamento di default

Di default, la definizione di una classe Java pu`o essere utilizzata solo dalle classi all’interno del suo stesso package.

p a c k a g e app . s t a c k ;

c l a s s S t a c k { int[] d a t a ; int n d a t a ;

v o i d p u s h (int i ) { ...

}

int pop () {

...

} }

(42)

Modificatore public

Come usare public

Java richiede al programmatore di esplicitare quali classi e quali membri possano essere utilizzati all’esterno del package. A questo scopo Java riserva il modificatore public da utilizzare prima della dichiarazione della classe o di un membro.

p u b l i c c l a s s S t a c k { int[] d a t a ;

int n d a t a ;

p u b l i c v o i d p u s h (int i ) { ...

}

p u b l i c int pop () { ...

} }

(43)

Modificatore public

Le specifiche del linguaggio richiedono che il codice sorgente di classe pubblica sia memorizzata in un file avente lo stesso nome della classe (incluse maiuscole e minuscole), ma con estensione

“.java”.

Come conseguenza alla regola, pu`o esistere solo una classe pubblica per ogni file di sorgente. Questa regola `e rinforzata dal compilatore che scrive il bytecode di ogni classe in un file avente lo stesso nome della classe (incluse maiuscole e minuscole), ma con estensione “.class”.

(44)

Package

Dal momento che le classi possono essere organizzate in package, `e necessario specificare a quale package una classe appartenga, pena l’incapacit`a della virtual machine di trovarla.

Un modo per indicare il package a cui una classe appartiene

`e quello di specificare il package ad ogni chiamata alla classe ossia utilizzando nomi qualificati.

i m p o r t app . s t a c k . S t a c k ;

oppure mediante l’uso di wildcard:

i m p o r t app . s t a c k .*;

che risolve il nome di tutte le classi pubbliche di un package.

(45)

Esempio3

Utilizzando la classe stack definita in precedenza, scrivere un ciclo while che stampi tutti gli interi pari da 1 a 13 inserendoli nello stack. La definizione di classe di stack dovr`a essere memorizzato nel package “esempi.lab”.

(46)

Incapsulamento

Definizione

L’incapsulamento di oggetti `e il processo di mascheramento dei dettagli dell’implementazione ad altri oggetti per evitare riferimenti incrociati. I programmi scritti con questa tecnica risultano molto pi`u leggibili e limitano i danni dovuto alla propagazione di bachi.

Nascondendo i dettagli, possiamo assicurare a chi utilizza l’oggetto che ci`o che sta utilizzando `e sempre in uno stato consistente a meno di bug dell’oggetto stesso. Uno stato consistente `e uno stato permesso dal disegno di un oggetto. `E per`o importante notare che uno stato consistente non corrisponde sempre allo stato aspettato dall’utente dell’oggetto.

(47)

Public, protected, private

Modificatori

I modificatori di accesso determinano ci`o che fa parte dell’interfaccia pubblica o privata

public: una classe, un metodo o un campo pubblico pu`o essere visto in qualunque parte del codice

protected: un metodo o un campo protetto pu`o essere visto solo nelle sottoclassi della classe che lo dichiara

private: un metodo o un campo privato pu`o essere visto solo nella classe che lo dichiara

package friendly: una classe, un metodo o un campo senza modificatori espliciti ha visibilit`a di default (visibile a livello di package)

(48)

Modificatore private

Il modificatore private realizza incapsulamento a livello di definizione di classe e serve a definire membri che devono essere utilizzati solo da altri membri della stessa classe di definizione.

p r i v a t e i d e n t i f i c a t a v a r _ n a m e ;

p r i v a t e r e t u r n _ t y p e m e t h o d _ n a m e ( a r g _ t y p e n a m e [ ,...]) {

i s t r u z i o n i }

(49)

Modificatore public

Il modificatore public consente di definire classi o membri di una classe visibili da qualsiasi classe all’interno dello stesso package e non.

Tipicamente metodi membro public utilizzano membri private per implementare le funzionalit`a dell’oggetto.

p u b l i c i d e n t i f i c a t a v a r _ n a m e ;

p u b l i c r e t u r n _ t y p e m e t h o d _ n a m e ( a r g _ t y p e n a m e [ ,...]) {

i s t r u z i o n i }

(50)

Modificatore protected

Membri di una classe dichiarati protected possono essere utilizzati sia dai membri della stessa classe che da altre classi purch´e appartenenti allo stesso package

p r o t e c t e d i d e n t i f i c a t a v a r _ n a m e ;

p r o t e c t e d r e t u r n _ t y p e m e t h o d _ n a m e ( a r g _ t y p e n a m e [ ,...]) {

i s t r u z i o n i }

(51)

Esempio di incapsulamento: classe Impiegato

p a c k a g e it . u n i t s . e s e m p i o ;

p u b l i c c l a s s I m p i e g a t o {

p r i v a t e S t r i n g n o m e ;

p r i v a t e b o o l e a n a f f a m a t o = t r u e; p u b l i c b o o l e a n h a i F a m e () {

r e t u r n a f f a m a t o ; }

p u b l i c S t r i n g n o m e () { r e t u r n n o m e ;

}

p u b l i c v o i d v a i A P r a n z o ( S t r i n g l u o g o ) { // m a n g i a

a f f a m a t o = f a l s e; }

}

(52)

Esempio di incapsulamento: classe DatoreDiLavoro

p a c k a g e it . u n i t s . e s e m p i o ;

p u b l i c c l a s s D a t o r e D i L a v o r o {

p u b l i c v o i d s i i C o r r e t t o C o n I m p i e g a t o ( I m p i e g a t o i m p i e g a t o ) {

// if ( i m p i e g a t o . a f f a m a t o ) i l l e g a l e , p r i v a t e ! // i m p i e g a t o . a f f a m a t o = true , i l l e g a l e , p r i v a t e ! if ( i m p i e g a t o . h a i F a m e ())

{

i m p i e g a t o . v a i A P r a n z o ( " R i s t o r a n t e " );

} } }

(53)

Completiamo l’esempio

Scriviamo il codice per far funzionare le due classi definite nei lucidi precedenti.

(54)

Costruttori

Definizione

I costruttori sono metodi speciali chiamati quando viene creata una nuova istanza di classe e servono ad inizializzare lo stato iniziale dell’oggetto. Questi metodi hanno lo stesso nome della classe di cui sono membro e non restituiscono nessun tipo. Se una classe non `e provvista di costruttore, Java ne utilizza uno speciale di default.

Operatore new

Per creare un oggetto attivo dalla sua definizione di classe, Java mette a disposizione l’operatore new.

La sintassi dell’operatore new prevede un tipo seguito da un insieme di parentesi. Le parentesi indicano che per creare l’oggetto verr`a chiamato il costruttore.

(55)

Esempio costruttore 1/2

p a c k a g e it . u n i t s . e s e m p i o ; p u b l i c c l a s s S t a c k {

p r i v a t e int m a x s i z e ; p r i v a t e int[] d a t a ; p r i v a t e int f i r s t ;

p u b l i c S t a c k () // c o s t r u t t o r e {

m a x s i z e = 10;

d a t a = new int[ 1 0 ] ; f i r s t = 0;

}

int pop () {

if ( f i r s t > 0) {

first - -;

r e t u r n d a t a [ f i r s t ];

}

r e t u r n 0;

}

(56)

Esempio costruttore 2/2

v o i d p u s h (int i ) { if ( f i r s t < m a x s i z e ) {

d a t a [ f i r s t ] = i ; f i r s t ++;

} }

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) { S t a c k s = new S t a c k ();

s . p u s h ( 5 ) ;

S y s t e m . out . p r i n t l n ( " Ho l e t t o " + s . pop ( ) ) ; }

(57)

Overloading dei costruttori

Al programmatore `e consentito scrivere pi`u di un costruttore per una data classe a seconda delle necessit`a di disegno dell’oggetto, permettendogli di passare diversi insiemi di dati di inizializzazione.

p u b l i c S t a c k () { m a x s i z e = 10:

d a t a = new int[ 1 0 ] ; f i r s t = 0;

}

p u b l i c S t a c k (int s i z e ) { m a x s i z e = s i z e ;

d a t a = new int[ m a x s i z e ];

f i r s t = 0;

}

Stack s = new Stack(25);

(58)

Chiamate incrociate di costruttori

Guardando la definizione di Stack, notiamo che i due costruttori fanno esattamente la stessa cosa. Per ridurre la quantit`a di codice, possiamo chiamare un costruttore da un altro. Per chiamare un costruttore da un altro, `e necessario utilizzare una sintassi speciale.

p u b l i c S t a c k () { t h i s( 1 0 ) ; }

p u b l i c S t a c k (int m a x s i z e ) { d a t a = new int[ m a x s i z e ];

t h i s. m a x s i z e = m a x s i z e ; f i r s t = 0;

}

Una chiamata cross–call tra costruttori, DEVE essere la prima riga di codice del costruttore chiamante.

(59)

Esempio5

Definire un oggetto chiamato Set che rappresenta un insieme di interi.

L’insieme deve avere al massimo tre metodi:

boolean isMember(int); //Ritorna true se il numero `e nell’insieme

void addMember(int); //Aggiunge un numero all’insieme void showSet(); //Stampa a video il contenuto dell’insieme nel formato:

1, 4, 5, 12

(60)

Cosa ` e l’ereditariet` a

Definizione

L’ereditariet`a `e la caratteristica dei linguaggi object oriented che consente di utilizzare classi come base per la definizione di nuovi oggetti che ne specializzano il concetto.

Essa permette di:

aggiungere funzionalit`a

rischi minimi per le funzionalit`a esistenti

auto–documentante rispetto ai linguaggi procedurali Aspetti essenziali dell’ereditariet`a sono l’overload e l’overriding dei metodi.

(61)

Ereditariet` a singola

Object

ClassB

ClassB1

ClassC ClassD

ClassD1 ClassD2

(62)

Ereditariet` a

Ogni volta che si utilizza una classe per ereditariet`a ci si riferisce a questa come alla “classe base” o “superclasse”.

Quando definiamo nuovi oggetti utilizzando l’ereditariet`a, tutte le funzionalit`a della classe base sono trasferite alla nuova classe detta

“classe derivata“ o “sottoclasse”.

Concetti base

i membri della classe base sono “concettualmente” copiati nella nuova classe

consente alla classe derivata di modificare la superclasse ogni aggiunta o modifica ai metodi della superclasse sar`a applicata solo alle classe derivata

(63)

Considerazioni sull’ereditariet` a

Tramite questa tecnica `e possibile creare nuove variet`a di entit`a gi`a definite mantenendone tutte le caratteristiche e le funzionalit`a.

Questo significa che se una applicazione `e in grado di utilizzare una classe base, sar`a in grado di utilizzarne la derivata allo stesso modo. Per questi motivi, `e importante che una classe base

rappresenti le funzionalit`a generiche delle varie specializzazioni che andremo a definire.

(64)

Overload di metodi 1/2

Definizione

Fare l’overloading di un metodo significa, in generale, dotare una classe di metodi aventi stesso nome, ma con parametri differenti.

p u b l i c c l a s s V e i c o l o { S t r i n g n o m e ;

int v e l o c i t a ; int d i r e z i o n e ;

f i n a l s t a t i c int D I R I T T O = 0;

f i n a l s t a t i c int S I N I S T R A = 1;

f i n a l s t a t i c int D E S T R A = 2;

(65)

Overload di metodi 2/2

p u b l i c V e i c o l o () { ...

}

p u b l i c v o i d m u o v i () { v e l o c i t a = 1;

}

p u b l i c v o i d m u o v i (int q u a l e V e l o c i t a ) { v e l o c i t a = q u a l e V e l o c i t a ;

}

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) { V e i c o l o v = new V e i c o l o ();

v . m u o v i ();

v . m u o v i ( 1 0 ) ; }

}

(66)

Estendere una classe

Definita la classe base Veicolo, sar`a possibile definire nuovi tipi di veicoli estendendo la classe generica.

class nome classe extends nome super classe

c l a s s M a c c h i n a e x t e n d s V e i c o l o { p u b l i c M a c c h i n a () {

v e l o c i t a = 0;

d i r e z i o n e = D I R I T T O ; n o m e = " M a c c h i n a " ; }

}

Estendendo la classe Veicolo, ne ereditiamo tutti i dati membro ed i metodi. L’unico cambiamento che abbiamo dovuto apportare `e quello di creare un costruttore ad hoc. Il nuovo costruttore semplicemente modifica il contenuto della variabile nome affinch´e l’applicazione stampi i messaggi corretti.

(67)

Usare la nuova classe Macchina

p u b l i c c l a s s A u t i s t a {

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g v ) { M a c c h i n a f i a t = new M a c c h i n a ();

f i a t . m u o v i ();

} }

(68)

Ereditariet` a ed incapsulamento

Come si comportano i modificatori public, private e protected quando sono ereditati da altre classi?

public consente di dichiarare dati e metodi membro visibili

private nasconde completamente dati e metodi membro protected... vediamo

(69)

Modificatore protected 1/3

p a c k a g e p a c k b a s e ;

c l a s s C l a s s e B a s e {

p r o t e c t e d int d a t o P r o t e t t o ; p r o t e c t e d v o i d m e t o d o P r o t e t t o () {

...

} }

Proviamo ad estendere questa classe nello stesso package.

(70)

Modificatore protected 2/3

p a c k a g e p a c k b a s e ;

c l a s s A l t r a C l a s s e {

C l a s s e B a s e a = new C l a s s e B a s e ();

v o i d m e t o d o () { a . m e t o d o P r o t e t t o ();

} }

Lecito in quanto siamo nello stesso package. Proviamo ora ad usare qualcosa di protetto da una classe in un altro package.

(71)

Modificatore protected 3/3

p a c k a g e a l t r o p a c k a g e ; i m p o r t p a c k b a s e ;

c l a s s T e r z a C l a s s e e x t e n d s C l a s s e B a s e {

v o i d m e t o d o I n t e r n o ( C l a s s e B a s e cb , T e r z a C l a s s e tc ) { tc . m e t o d o P r o t e t t o (); // L e g a l e

cb . m e t o d o P r o t e t t o (); // I l l e g a l e }

}

Ricapitolando quindi...

(72)

Riassunto modificatori

Class Package

Subclass (same pkg)

Subclass

(diff pkg) World

public * * * * *

protected * * * *

friendly * * *

private *

(73)

Considerazioni sul costruttore

Considerazioni

Negli esempi precedenti si nota facilmente che il codice del metodo costruttore della classe Veicolo `e molto simile a quello del

costruttore della classe Macchina

Potrebbe tornare utile utilizzare il costruttore della classe base...

Cosa potrebbe succedere se sbagliassimo qualcosa nella definizione del costruttore della classe derivata?

Cosa succederebbe se nella classe base ci fossero dei dati privati che il costruttore della classe derivata non pu`o aggiornare?

(74)

Soluzione per il costruttore

Ogni classe deve avere un costruttore Costruttore di default, con codice vuoto

Una classe derivata, pu`o chiamare il costruttore della classe base mediante la sintassi:

super(argument list)

p u b l i c c o s t r u t t o r e D e f i n i t o D a U t e n t e () { s u p e r( 2 3 ) ;

int i ; }

Se l’utente non effettua una chiamata esplicita al costruttore della classe base, Java esegue implicitamente tale chiamata (senza argomenti).

(75)

Aggiungere metodi

Quando estendiamo una classe, possiamo aggiungere nuovi metodi alla classe derivata.

Questo ci permette di implementare caratteristiche particolari non definite nella definizione generica della classe base.

p u b l i c c l a s s M a c c h i n a e x t e n d s V e i c o l o { p u b l i c M a c c h i n a () {

v e l o c i t a = 0;

d i r e z i o n e = D I R I T T O ; n o m e = " M a c c h i n a " ; }

p u b l i c v o i d s u o n a () {

S y s t e m . out . p r i n t l n ( n o m e + " s u o n a t o il c l a c s o n " );

} }

Quinti Autista pu`o ora chiamare anche il metodo suona().

(76)

Overriding di metodi

Idea

Se un metodo ereditato non lavorasse correttamente rispetto a quanto ci aspettiamo dalla specializzazione del concetto definito nella classe base, Java ci consente di riscrivere il metodo originale.

Riscrivendo nuovamente il metodo solo nella nuova classe, non c’`e pericolo che la classe base venga manomessa. Il nuovo metodo verr`a chiamato al posto del vecchio anche se la chiamata venisse effettuata da un metodo ereditato dalla classe base.

(77)

Chiamare medodo classe base

Utilizzo di super

La parola chiave super pu`o essere utilizzata anche nel caso in cui sia necessario richiamare un metodo della super classe ridefinito nella classe derivata con il meccanismo di overriding.

p u b l i c c l a s s M a c c h i n a e x t e n d s V e i c o l o { p u b l i c v o i d m u o v i (int q u a l e _ v e l o c i t a ) {

s u p e r. m u o v i ( q u a l e _ v e l o c i t a );

...

} }

In questo caso super ha lo stesso significato di una variabile reference con la differenza che viene istanziato dalla JVM e referenzia sempre la superclasse della classe attiva ad ogni istante.

(78)

Variabili reference

Una volta che una classe Java `e stata derivata, Java consente alle variabili reference che rappresentano il tipo della classe base di referenziare ogni istanza di un oggetto derivato da essa nella gerarchia definita dalla ereditariet`a.

V e i c o l o v = new M a c c h i n a ();

v . s u o n a (); // C h i a m a il m e t o d o di M a c c h i n a

Tutti gli oggetti derivati hanno sicuramente almeno tutti i metodi della classe base.

Nel caso in cui un metodo sia stato ridefinito mediante overriding, queste tipo di referenziamento comunque effettuer`a una chiamata al nuovo metodo.

(79)

casting

Il cast di un tipo consente di dichiarare che una variabile reference temporaneamente rappresenter`a un tipo differente da quello rappresentato al compile-time. La sintassi di una cast di tipo `e la seguente:

(new type) variabile

Dove new type `e il tipo desiderato e variable `e la variabile che vogliamo convertire temporaneamente.

(80)

instanceof

Dal momento che in una applicazione Java esistono variabili reference in gran numero, `e a volte utile determinare al run-time che tipo di oggetto la variabile sta referenziando.

A tal fine Java supporta l’operatore booleano instanceof che controlla il tipo di oggetto referenziato al run-time da una variabile reference.

A instanceof B

Dove A rappresenta una variabile reference, e B un tipo referenziabile.

(81)

java.lang.Object

Tutte le classi estendono un’altra classe

Se non si estende esplicitamente un’altra classe, si estende (implicitamente) la classe Object

Tutte le classi ereditano (direttamente o indirettamente) da Object

Alcuni metodi definiti da Object

toString(): rappresentazione a stringa dell’oggetto

hashCode(): intero che identifica univocamente un oggetto equals(Object o): restituisce true se l’oggetto `e uguale all’argomento (confronta lo stato degli oggetti)

finalize(): termina l’oggetto

toString() viene usato da System.out.print() per “visualizzare il

(82)

Esempio6

Creare, a partire dalla classe Veicolo, nuovi tipi di veicolo mediante il meccanismo della ereditariet`a: Cavallo, Macchina. Creare Driver per “pilotare” un veicolo.

(83)

Eccezioni

Definizione

Le eccezioni sono utilizzate da Java in quelle situazioni in cui sia necessario gestire condizioni anomale, ed i normali meccanismi sono insufficienti ad indicare l’errore. Formalmente, una eccezione

`e un evento che si scatena durante la normale esecuzione di un programma, causando l’interruzione del normale flusso di esecuzione della applicazione.

Spesso situazioni del genere sono legate all’inizializzazione dei costruttori che non hanno possibilit`a di restituire uno stato di ritorno.

Le eccezioni facilitano la vita al programmatore fornendo un meccanismo flessibile per descrivere eventi che, in mancanza delle quali, risulterebbero difficilmente gestibili

(84)

Propagazione

Il punto di forza del meccanismo delle eccezioni consiste nel consentire la propagazione di un oggetto a ritroso, attraverso la sequenza corrente di chiamate tra metodi.

Opzionalmente, ogni metodo pu`o fermare la propagazione e gestire la condizione di errore utilizzando le informazioni trasportate, oppure continuare la propagazione ai metodi subito adiacenti nella sequenza di chiamate.

Ogni metodo che non sia in grado di gestire l’eccezione viene interrotto nel punto in cui aveva chiamato il metodo che sta propagando l’errore.

Se la propagazione raggiunge l’entry point della applicazione e non viene arrestata, l’applicazione viene terminata.

(85)

Propagazione

c l a s s E x a m p l e { d o u b l e m e t o d o 1 () {

d o u b l e d ;

d = 4 . 0 / m e t o d o 2 ();

S y s t e m . out . p r i n t l n ( d );

}

f l o a t m e t o d o 2 () { f l o a t f ;

f = m e t o d o 3 ();

f = f * f ; r e t u r n f ; }

int m e t o d o 3 () {

if ( c o n d i z i o n e ) r e t u r n e s p r e s s i o n e ; e l s e // g e n e r a un ’ e c c e z i o n e e p r o p a g a }

}

Immagino di chiamare metodo1() → eccezione!

(86)

Propagazione oggetti

Quali oggetti vengono propagati

Gli oggetti da propagare come eccezioni devono derivare dalla classe base java.lang.Exception.

Gli oggetti che vengono propagati sono derivati dalla classe java.lang.Throwable che contiene i metodi per la gestione dello stack tracing. I suoi 2 costruttori sono:

Throwable() Throwable(String)

Entrambi inizializzano lo stack, il secondo lo inizializza con un messaggio dettagliato, accessibile tramite toString().

(87)

Gestione della propagazione

Per poter gestire la propagazione dell’oggetto lungo la sequenza delle chiamate, i due costruttori effettuano una chiamata al metodo public Throwable fillInStackTrace()

il quale registra lo stato dello stack di sistema.

Il metodo

public void printStackTrace()

consente invece di stampare sullo standard error la sequenza restituita dal metodo precedente.

Exception/Throwable

La classe Exception `e derivata dalla Throwable che, a sua volta, deriva da Object.

Le altre eccezioni del sistema derivano tutte da Exception.

(88)

Esempio eccezione

c l a s s C l a s s e E s e m p i o {

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g v ) { m e t o d o 1 (n u l l);

}

s t a t i c v o i d m e t o d o 1 (int[] a ) { m e t o d o 2 ( a );

}

s t a t i c v o i d m e t o d o 2 (int[] b ) { S y s t e m . out . p r i n t l n ( b [ 0 ] ) ; }

}

Exception in thread "main" java.lang.NullPointerException at ClasseEsempio.metodo2(ClasseEsempio.java:14)

at ClasseEsempio.metodo1(ClasseEsempio.java:9) at ClasseEsempio.main(ClasseEsempio.java:5)

(89)

Eccezioni personalizzate

c l a s s O u t O f D a t a E x c e p t i o n e x t e n d s E x c e p t i o n { S t r i n g e r r o r m e s s a g e ;

p u b l i c O u t O f D a t a E x c e p t i o n ( S t r i n g s ) { s u p e r( s );

e r r o r m e s s a g e = s ; }

p u b l i c O u t O f D a t a E x c e p t i o n () { s u p e r();

e r r o r m e s s a g e = " O u t O f D a t a E x c e p t i o n " ; }

p u b l i c S t r i n g t o S t r i n g () { // da O b j e c t r e t u r n e r r o r m e s s a g e ;

}

(90)

throw

Le eccezioni vengono propagate a ritroso attraverso la sequenza dei metodi chiamanti tramite l’istruzione throw, che ha sintassi:

throw Object instance

dove Object instance `e un oggetto di tipo Throwable.

Questo metodo causa la terminazione del metodo corrente (come se fosse stata utilizzata l’istruzione return), ed invia l’oggetto specificato al metodo chiamante.

(91)

Clausola throws

Questo metodo causa la terminazione del metodo corrente (come se fosse stata utilizzata l’istruzione return), ed invia l’oggetto specificato al metodo chiamante.

r e t u r n _ t y p e m e t h o d _ n a m e ( p a r a m _ l i s t ) t h r o w s T h r o w a b l e _ t y p e {

M e t h o d B o d y }

Immaginiamo di gestire un’eccezione nella classe Stack:

v o i d p u s h (int i ) t h r o w s O u t O f D a t a E x c e p t i o n { if ( first < m a x s i z e ) {

d a t a [ f i r s t ] = i ; f i r s t ++;

}

e l s e t h r o w new O u t O f D a t a E x c e p t i o n ( " E r r o r e ins . " );

(92)

Istruzioni try/catch

Per evitare che l’eccezione generata si propaghi fino all’entry point e causi cos`ı la terminazione della applicazione, si usano le istruzioni try, catch e finally (istruzioni guardiane).

try {

i s t r u z i o n i }

c a t c h ( E x c e p t i o n v a r 1 ) { i s t r u z i o n i

}

c a t c h ( E x c e p t i o n v a r 2 ) { }

f i n a l l y {

i s t r u z i o n i e s e g u i t e s e m p r e }

Se una istruzione nel blocco try genera un’eccezione, le rimanenti istruzioni nel blocco non vengono eseguite. L’esecuzione di un

(93)

Esempio try/catch

try {

f1 (); // Una e c c e z i o n e in q u e s t o p u n t o fa s a l t a r e f2 () // e f3 ()

f2 (); // Una e c c e z i o n e in q u e s t o p u n t o fa s a l t a r e f3 () f3 ();

}

c a t c h ( I O E x c e p t i o n _e ) {

S y s t e m . out . p r i n t l n ( _e . t o S t r i n g ( ) ) ; }

c a t c h ( N u l l P o i n t e r E x c e p t i o n _ n p e ) { S y s t e m . out . p r i n t l n ( _ n p e . t o S t r i n g ( ) ) ; }

(94)

Eccezioni multiple

Dato che tutte le eccezioni sono derivate da Exception, possiamo catturare eccezioni multiple come mostrato nel seguente codice:

try {

f1 (); // Una e c c e z i o n e in q u e s t o p u n t o fa s a l t a r e f2 () // e f3 ()

f2 (); // Una e c c e z i o n e in q u e s t o p u n t o fa s a l t a r e f3 () f3 ();

}

c a t c h ( j a v a . l a n g . E x c e p t i o n _e ) { // S i m i l e a d e f a u l t s w i t c h S y s t e m . out . p r i n t l n ( _e . t o S t r i n g ( ) ) ;

}

c a t c h ( N u l l P o i n t e r E x c e p t i o n _ n p e ) { // I n u t i l e ! S y s t e m . out . p r i n t l n ( _ n p e . t o S t r i n g ( ) ) ;

}

(95)

finally

Utilizzo

Questo blocco vuole fornire ad un metodo la possibilit`a di eseguire sempre un certo insieme di istruzioni a prescindere da come il metodo manipola le eccezioni.

I blocchi finally non possono essere evitati dal controllo di flusso della applicazione. Le istruzioni break, continue o return

all’interno del blocco try o all’interno di un qualunque blocco catch verranno eseguite solo dopo l’esecuzione del codice nel blocco finally.

Solo una chiamata del tipo System.exit() ha la capacit`a di evitare l’esecuzione del blocco di istruzioni in questione.

(96)

Ereditariet` a avanzata

Uno dei limiti pi`u comuni della ereditariet`a singola `e che non prevede l’utilizzo di una classe base come modello puramente concettuale, ossia priva della implementazione delle funzioni base.

Inoltre JAVA non consente l’ereditariet`a multipla come in C++.

JAVA risolve questo problema ricorrendo all’uso di interfacce e classi astratte.

interface: non contengono implementazioni delle funzionalit`a descritte

abstract: consentono di non implementare tutte le caratteristiche dell’oggetto rappresentato

Polimorfismo `e la terza parola chiave del paradigma ad oggetti:

un’interfaccia, molti metodi.

Ci`o significa che possiamo definire una interfaccia unica da utilizzare in molti casi collegati logicamente tra di loro.

(97)

Interface

Definizione

Una interfaccia Java rappresenta un prototipo e consente al programmatore di definire lo scheletro di una classe: nomi dei metodi, tipi ritornati, lista dei parametri.

Se vengono definiti dati membro primitivi, essi vengono considerati come static, final.

(98)

Dichiarazione interface

i n t e r f a c e i d e n t i f i c a t o r e { c o r p o _ i n t e r f a c c i a

}

Caso reale:

i n t e r f a c e S t a c k {

p u b l i c v o i d p u s h (int i );

p u b l i c int pop ();

}

(99)

Implementazione interface

c l a s s n o m e _ c l a s s e i m p l e m e n t s n o m e _ i n t e r f a c c i a { c o r p o _ i n t e r f a c c i a

}

Esempio:

p u b l i c i n t e r f a c e S t a c k D e f { p u b l i c v o i d p u s h (int i );

p u b l i c int pop ();

}

c l a s s S t a c k i m p l e m e n t s S t a c k D e f { p u b l i c v o i d p u s h (int i ) {

...

}

p u b l i c int pop () { ...

} }

(100)

Implementazione

Come si implementa

Quando una classe implementa una interfaccia `e obbligata ad implementarne i prototipi dei metodi definiti nel corpo. In caso contrario il compilatore generer`a un messaggio di errore.

Conseguenza diretta sar`a la possibilit`a di utilizzare le interfacce come tipi per definire variabili reference in grado di referenziare oggetti costruiti mediante implementazione di una interfaccia.

Se l’operatore extends limitava la derivazione di una classe a partire da una sola classe base, l’operatore implements ci consente di implementare pi`u di una interfaccia (ereditariet`a multipla).

(101)

Classi abstract

Definizione

Capitano casi in cui solo una parte della interfaccia base debba essere implementata. In questo caso si usano le classi di tipo abstract.

Per estendere le classi abstract si usa l’istruzione extends.

Le abstract non sono “complete“, quindi non possono essere istanziate.

a b s t r a c t c l a s s n o m e _ c l a s s e { d a t a _ m e m b e r s

a b s t r a c t _ m e t h o d s n o n _ a b s t r a c t _ m e t h o d s }

Quando una nuova classe viene derivata a partire dalla classe astratta, il compilatore richiede che tutti i metodi astratti vengano definiti. Se la necessit`a del momento costringe a non definire questi

(102)

interface vs abstract

interface abstract

Istanziabile no no

Fields static/final s`ı

Costruttore no s`ı

Metodi statici java8+ s`ı

Dichiarazione metodi no s`ı

Implementazione metodi java8+ (default) s`ı

(103)

Esempio4

Usare un’interfaccia per implementare Veicolo.

(104)

Thread

Multithread in Java

Java `e un linguaggio multihread che consente di creare applicazioni in grado di utilizzare la concorrenza logica tra i processi,

continuando a condividere tra i thread lo spazio in memoria riservato ai dati.

Dal punto di vista dell’utente, i thread logici appaiono come una serie di processi che eseguono parallelamente le loro funzioni.

Dal punto di vista della applicazione rappresentano una serie di processi logici che, da una parte condividono la stessa memoria della applicazione che li ha creati, dall’altra concorrono con il processo principale al meccanismo di assegnazione della CPU.

(105)

Osservazioni

Esistono dei thread che vengono eseguiti senza che l’utente se ne renda conto:

Thread per la gestione delle interfacce grafiche che si occupa della gestione degli eventi e di aggiornare i contenuti grafici.

Il garbage collector `e un thread responsabile di trovare gli oggetti non pi`u referenziati e quindi da eliminare dallo spazio di memoria della applicazione.

Lo stesso metodo main() di una applicazione viene avviato come un thread sotto il controllo della Java Virtual Machine.

(106)

java.lang.Thread

In Java, un modo per definire un oggetto thread `e quello di utilizzare l’ereditariet`a derivando il nuovo oggetto dalla classe base java.lang.Thread.

Metodi di java.lang.Thread

run(): `e il metodo utilizzato per implementare le funzionalit`a eseguite thread → override!

start(): causa l’esecuzione del thread

destroy(): distrugge il thread e rilascia le risorse allocate (deprecated)

(107)

Esempio di thread

c l a s s P r i m o T h r e a d e x t e n d s T h r e a d { int s e c o n d i ;

P r i m o T h r e a d (int s e c o n d i ) { t h i s. s e c o n d i = s e c o n d i ; }

p u b l i c v o i d run () { // Fai q u a l c o s a }

}

(108)

Interfaccia Runnable

PROBLEMA: supponiamo ora che la nostra classe PrimoThread sia stata definita a partire da una classe generale diversa da java.lang.Thread. A causa dei limiti stabiliti dalla ereditariet`a singola, sar`a impossibile creare un thread utilizzando lo stesso meccanismo definito...

Usando le interfacce si pu`o ovviare a questo problema

p u b l i c i n t e r f a c e R u n n a b l e { p u b l i c v o i d run ();

}

(109)

Soluzione del problema

c l a s s C l a s s e B a s e { C l a s s e B a s e () {

...

}

p u b l i c v o i d f a i Q u a l c o s a () { ...

} }

e quindi

c l a s s P r i m o T h r e a d e x t e n d s C l a s s e B a s e i m p l e m e n t s R u n n a b l e { int s e c o n d i ;

...

p u b l i c v o i d run () { // Fai q u a l c o s a }

(110)

Per lanciare il thread

p u b l i c c l a s s L a n c i a T h r e a d {

p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) { P r i m o T h r e a d t = new P r i m o T h r e a d ( 1 0 ) ; t . s t a r t (); // C h i a m a il m e t o d o run () }

}

(111)

Sincronizzazione ed accesso ai dati

Concorrenza

Quando due o pi`u thread possono accedere ad un oggetto

contemporaneamente per modificarlo, il rischio a cui si va incontro

`e quello della corruzione dei dati rappresentati dall’oggetto utilizzato tra i thread in regime di concorrenza.

`E necessario che due (o pi`u) thread vengano sincronizzati, ovvero che mentre uno esegue l’operazione, l’altro deve rimanere in attesa.

Java fornisce un metodo per gestire la sincronizzazione tra thread mediante la parola chiave synchronized.

(112)

Come si usa synchronized

Il modificatore synchronized deve essere aggiunto alla

dichiarazione del metodo per assicurare che solo un thread alla volta sia in grado di utilizzare i dati.

c l a s s Set {

p r i v a t e int[] d a t a ; ...

b o o l e a n i s M e m b e r (int n ) {

// c o n t r o l l a se l ’ i n t e r o e ’ n e l l ’ i n s i e m e }

v o i d add (int n ) {

// a g g i u n g e n all ’ i n s i e m e }

}

Immaginiamo che 2 thread accedano ai dati di questa classe in manieraconcorrente→ dati corrotti!

Riferimenti

Documenti correlati

Il campo magnetico generato nel punto O sar` a dato dalla somma dei campi magnetici generati dai due fili, che a sua volta sono, per ciascun filo, la somma dei campi generati dai

Gli oggetti quasi-statici vengono definiti come oggetti che generano percezioni sensoriali da parte del robot anche per inter- valli di tempo prolungati e che non possono

[r]

• Il metodo run della classe di libreria Thread definisce l’insieme di statement Java che ogni thread (oggetto della classe) eseguirà.. concorrentemente con gli

Verifica se i tre punti sono collineari (cioè se giacciono su una stessa retta) oppure no; nel primo caso visualizza all’utente il messaggio “punti collineari: true” , mentre

Verifica se i tre punti sono collineari (cioè se giacciono su una stessa retta) oppure no; nel primo caso visualizza all’utente il messaggio “punti collineari: true” , mentre

Suggerimento: usare la classe Integer ed il metodo parseInt per convertire i caratteri della stringa in cifre

Suggerimento: usare la classe Integer ed il metodo parseInt per convertire i caratteri della stringa in