Programmazione ad oggetti - Dipartimento di Informatica

Linguaggi ad oggetti
Linguaggi di
Programmazione: Paradigmi
di Programmazione
• I linguaggi di programmazione ad oggetti
consentono di applicare metodologie di sviluppo di
programmi "object oriented", ossia basate sugli
oggetti (dati) che il sistema software manipola.
• Questa metodologia si contrappone a quella più
tradizionale di sviluppare un programma secondo
un approccio funzionale (programmazione
strutturata).
PROGRAMMAZIONE AD OGGETTI
(lucidi originali di Alberto Martelli)
Matteo Baldoni
Dipartimento di Informatica - Universita` degli Studi di Torino
C.so Svizzera, 185 - I-10149 Torino (Italy)
e-mail: [email protected] - URL: http://www.di.unito.it/~baldoni
Linguaggi di Programmazione: Paradigmi di Programmazione
I principali linguaggi ad
oggetti
Programmazione ad oggetti
• In molti casi l'organizzazione ad oggetti risulta la
più naturale perché rispecchia in modo diretto il
mondo che si vuole rappresentare:
• Simula: progettato nel 1967 - capostipite dei
linguaggi ad oggetti
– simulazione (automobili, semafori, aerei, …)
• Smalltalk: linguaggio ad oggetti "puro" linguaggio "dinamico” non c'è controllo statico dei
tipi
– software grafico (finestre, bottoni, menu, …)
• Progetto object oriented di software: costruzione di
sistemi software come collezioni strutturate di
implementazioni di tipi di dati astratti (B. Meyer)
Linguaggi di Programmazione: Paradigmi di Programmazione
3
• C++: linguaggio "ibrido" - garantisce la
compatibilità con il C
• Java: il più recente.
Linguaggi di Programmazione: Paradigmi di Programmazione
Java
4
Java
• Le caratteristiche principali di Java
• Indipendente dall'architettura
– il compilatore genera codice intermedio (bytecode) che
viene interpretato
• Object oriented:
– progettato per essere un linguaggio ad oggetti, anche se
meno puro di Smalltalk
• Applicazioni su internet
– applet
• Robusto
– sicurezza
– non ci sono puntatori
• Ambiente ricco di tipi di dati predefiniti
– garbage collection
– grafica
• Distribuito
– programmazione su internet
– costrutti per la concorrenza
Linguaggi di Programmazione: Paradigmi di Programmazione
2
– accesso a database
5
Linguaggi di Programmazione: Paradigmi di Programmazione
6
1
Oggetti
Incapsulamento
Un oggetto rappresenta un dato, ed è costituito da
• I dati e le procedure che li manipolano sono
raggruppati in un’unica entità, l’oggetto.
• stato: collezione di variabili
• comportamento: collezione di operazioni
(metodi)
Esempio - contatore
STATO
int c;
METODI
void iniz(int i)
void incr()
void decr()
int val()
• Il mondo esterno ha accesso ai dati solo tramite
un insieme di operazioni (metodi) che
costituiscono l’interfaccia dell’oggetto. I dettagli
dell’implementazione sono nascosti
(INFORMATION HIDING)
inizializza il contatore a i
incrementa il contatore di 1
decrementa il contatore di 1
restituisce il valore del
contatore
Linguaggi di Programmazione: Paradigmi di Programmazione
• Un oggetto realizza una ASTRAZIONE DEI DATI
Linguaggi di Programmazione: Paradigmi di Programmazione
7
Contatore
Invio di Messaggi
• Un programma è costituito da un insieme di
oggetti.
• Gli oggetti sono dinamici - creati e distrutti
durante l'esecuzione del programma.
• Un oggetto A, per agire su un altro oggetto B, invia
un messaggio a B chiedendogli di eseguire uno dei
metodi della sua interfaccia.
int c;
void iniz(int i ) {c=1;}
void incr( ) {++c;}
void decr( ) {--c;}
int val( ) {return c;}
void iniz(int i )
void incr( )
void decr( )
int val( )
INTERFACCIA
A
IMPLEMENTAZIONE
CONTATORE
Linguaggi di Programmazione: Paradigmi di Programmazione
9
Invio di Messaggi
10
Invio di Messaggi
display
• invio di messaggio = invocazione di un metodo
• In Java, e altri linguaggi, si usa la notazione con il
punto: oggetto.metodo(…)
contatore
invia valore di c
0
c
cont1
esegui incr
3
cont2
bottone 3
bottone 1
B
esegui il metodo m1
• Lo scambio di messaggi è l'unico modo di
comunicare tra oggetti
Linguaggi di Programmazione: Paradigmi di Programmazione
finestra
8
10
bottone 2
Linguaggi di Programmazione: Paradigmi di Programmazione
11
int x,y;
cont1.incr();
cont2.decr();
x = cont1.val();
y = cont2.val();
x ha valore 4 e y ha valore 9
Linguaggi di Programmazione: Paradigmi di Programmazione
12
2
Invio di Messaggi
Classi
• In un linguaggio tradizionale, per eseguire una
operazione su un dato, dovremmo passare il dato
come parametro:
– incr(cont1) o iniz(cont1, 3)
• I più diffusi linguaggi ad oggetti sono basati sul
concetto di classe come insieme di oggetti con
struttura e comportamento simili
• La classe definisce un tipo
• Istanza di una classe = oggetto della classe
• Nella programmazione ad oggetti, invece, l'oggetto
su cui si esegue una operazione non viene passato
come parametro, perché figura già come
destinatario del messaggio (può essere considerato
come un parametro implicito)
– cont1.incr() o cont1.iniz(3)
Linguaggi di Programmazione: Paradigmi di Programmazione
13
Classi in Java
Classe
Contatore
• In Java:
class Contatore {
int c;
void iniz(int i) {c = i;}
void incr() {++c;}
void decr() {--c;}
int val() {return c;}
}
10
Linguaggi di Programmazione: Paradigmi di Programmazione
14
• Per realizzare information hiding si usano le parole
riservate
– public - interfaccia
– private - implementazione
• Per il momento trascuriamo questo aspetto
class Contatore {
private int c;
public void iniz(int i) {c = i;}
public void incr() {++c;}
public void decr() {--c;}
public int val() {return c;}
}
15
Linguaggi di Programmazione: Paradigmi di Programmazione
Variabili private
16
Tipi
class Contatore {
private int c;
public void iniz(int i) {c = i;}
public void incr() {++c;}
public void decr() {--c;}
public int val() {return c;}
}
• Si noti che, se la variabile c fosse public, il metodo
val sarebbe inutile: per conoscere il valore di un
contatore cont basterebbe usare cont.c
• Tuttavia è buna norma di programmazione
impedire l’accesso diretto alle variabili di un
oggetto, dichiarandole private.
Linguaggi di Programmazione: Paradigmi di Programmazione
cont2
3
Classi in Java
• Una classe realizza l'implementazione di un tipo di
dato astratto.
Linguaggi di Programmazione: Paradigmi di Programmazione
Istanze
cont1
17
• Java è un linguaggio tipato: tutte le variabili hanno
un tipo.
• Il tipo di una variabile deve sempre essere
dichiarato e può essere:
– una classe
– un tipo primitivo
Contatore cont;
int x,y;
char ch;
Linguaggi di Programmazione: Paradigmi di Programmazione
18
3
Tipi di dato primitivi
Come si crea un’istanza
• Java fornisce diversi tipi semplici primitivi.
• A differenza di altri linguaggi, la dimensione dei tipi
numerici è fissata per consentire la portabilità dei
programmi:
–
–
–
–
–
–
–
–
byte
short
int
long
float
double
char
boolean
8
16
32
64
32
64
16
bit
bit
bit
bit
bit
bit
bit (Unicode)
Linguaggi di Programmazione: Paradigmi di Programmazione
• new Contatore()
• Crea un nuovo oggetto di tipo Contatore e ne
restituisce il puntatore (handle)
• Tutti gli oggetti sono allocati dinamicamente
(quando si esegue la new) e sono manipolati
attraverso una handle (puntatore) (assegnamento,
passaggio di parametri)
19
Gestione della memoria
Linguaggi di Programmazione: Paradigmi di Programmazione
20
Gestione della memoria
STATICA
dati globali
• Nella maggior parte dei linguaggi di
programmazione le attivazioni di procedure sono
gestite con uno stack (pila)
• Quando una procedura è chiamata, si inserisce un
record di attivazione in cima alla pila, e lo si
toglie quando l'esecuzione della procedura termina
Codice
STACK
record di attivaz.
dati locali
• Un record di attivazione contiene le informazioni sul
controllo (indirizzo di ritorno) ed i dati locali
HEAP
dati dinamici
• Possibilità di chiamate ricorsive di procedure
Linguaggi di Programmazione: Paradigmi di Programmazione
21
Recupero della memoria
Linguaggi di Programmazione: Paradigmi di Programmazione
22
Allocazione dinamica
Contatore cont1, cont2;
• Garbage collection (Scheme, Prolog, Java)
cont1
cont2
• Il programmatore può solo allocare dati dinamici
• Una procedura di sistema, il garbage collector, si
preoccupa di recuperare tutte le aree di memoria
nello heap non più raggiungibili in modo da poterle
riutilizzare
• Altri linguaggi come Pascal o C lasciano al
programmatore la responsabilità di recuperare la
memoria, con possibilità di commettere errori
Linguaggi di Programmazione: Paradigmi di Programmazione
23
Linguaggi di Programmazione: Paradigmi di Programmazione
24
4
Allocazione dinamica
Contatore cont1, cont2;
cont1 = new Contatore();
cont2 = new Contatore();
cont1.iniz(3);
cont2.iniz(10);
Allocazione dinamica
Contatore cont1, cont2;
cont1 = new Contatore();
cont2 = new Contatore();
cont1.iniz(3);
cont2.iniz(10);
cont2 = cont1;
cont1
cont2
3
10
cont1
cont2
3
10
Questo oggetto non è più accessibile.
Può essere recuperato dal garbage
collector.
HEAP
Linguaggi di Programmazione: Paradigmi di Programmazione
HEAP
25
Puntatori
26
Come si inizializza un oggetto
• In Java non esistono puntatori espliciti
• Si può chiamare esplicitamente un metodo di
inizializzazione:
Contatore cont1;
cont1 = new Contatore();
cont1.iniz(3);
Contatore cont;
• Fino a quando non si esegue una new, la variabile
cont non è associata a nessun oggetto
• Viceversa in C++ si può dichiarare
sia Contatore cont1; sia Contatore *cont2;
• cont1 è associato ad un contatore creato
"staticamente”, cont2 è associato ad un contatore
creato dinamicamente (vedi Java)
Linguaggi di Programmazione: Paradigmi di Programmazione
27
Costruttori
class Contatore {
int c;
Contatore(int i) {c = i;}
void incr() {++c;}
void decr() {--c;}
int val() {return c;}
}
Linguaggi di Programmazione: Paradigmi di Programmazione
• L'inizializzazione di un oggetto è una operazione
molto importante.
• Java (e C++) forniscono la nozione di costruttore,
che consente di inizializzare automaticamente un
oggetto al momento della creazione.
Linguaggi di Programmazione: Paradigmi di Programmazione
28
Overloading dei costruttori
costruttore
• L'oggetto viene inizializzato al momento della
creazione, invocando automaticamente il
costruttore.
• L’istruzione Contatore cont1 = new Contatore(3); crea
un contatore e lo inizializza a 3.
Linguaggi di Programmazione: Paradigmi di Programmazione
29
class Contatore {
int c;
Contatore() {c = 0;}
Contatore(int i) {c = i;}
void incr() {++c;}
void decr() {--c;}
int val() {return c;}
}
Ci sono 2 costruttori
diversi, individuati dal
numero e tipo
degli argomenti.
Contatore cont1 = new Contatore();
Contatore cont2 = new Contatore(5);
//iniz. a 0
//iniz. a 5
Linguaggi di Programmazione: Paradigmi di Programmazione
30
5
Overloading di metodi
THIS
• Overloading: metodi diversi possono avere lo
stesso nome.
• I metodi "overloaded" si distinguono uno dall'altro
in base alla lista dei tipi degli argomenti.
• Come può un oggetto mandare un messaggio a se
stesso, ossia invocare un proprio metodo?
• Con la parola chiave this
class Contatore {
int c;
Contatore() {c = 0;}
Contatore(int i) {c = i;}
void incr() {++c;}
void incr(int n) {c += n;}
void decr() {--c;}
int val() {return c;}
}
class A {
...
void p() {...}
void m() { ... this.p(); ...}
}
In alcuni casi this
è indispensabile
si può anche scrivere solo p()
this viene aggiunto dal compilatore
Linguaggi di Programmazione: Paradigmi di Programmazione
31
Linguaggi di Programmazione: Paradigmi di Programmazione
32
I tipi semplici non sono
oggetti
THIS come costruttore
Contatore cont;
cont = new Contatore(3);
int x = 10;
• this da solo indica un costruttore della stessa
classe
cont
x
3
class Contatore {
int c;
Contatore(int n) {c=n;}
Contatore() {this(10);}
void incr() {++c;}
void decr() {--c;}
int val() {return c;}
}
chiama il costruttore
con un argomento
(inizializza il contatore
a 10)
Linguaggi di Programmazione: Paradigmi di Programmazione
33
Array in Java
• La dimensione è fissata al momento della creazione
oppure
oppure
• Esistono classi wrapper che
trasformano tipi semplici in
oggetti
HEAP
Linguaggi di Programmazione: Paradigmi di Programmazione
34
Array in Java
• Gli array in Java sono oggetti che vengono allocati
dinamicamente
Contatore cont[];
int num_giorni[];
• I tipi semplici, come ad es.
gli interi, non vengono
allocati dinamicamente nello
heap, a differenza di altri
linguaggi "puri" come
Smalltalk
Contatore[] cont;
int[] num_giorni;
• L'interprete controlla che gli indici siano sempre
nell'intervallo specificato al momento della
creazione
• num_giorni[13] darà errore a "runtime"
cont = new Contatore[3];
num_giorni = new int[12];
Linguaggi di Programmazione: Paradigmi di Programmazione
35
Linguaggi di Programmazione: Paradigmi di Programmazione
36
6
Array
Array
Contatore cont[];
Contatore cont[];
cont = new Contatore[3];
cont
cont
Linguaggi di Programmazione: Paradigmi di Programmazione
Linguaggi di Programmazione: Paradigmi di Programmazione
37
Array
Stringhe
Contatore cont[];
cont = new Contatore[3];
cont[0] = new Contatore(10);
• La libreria standard fornisce una classe predefinita
String
String s1 = "Buon";
String s2 = "giorno";
String saluto = s1 + s2;
contatore
cont
38
La stringa saluto ha valore:
“Buongiorno”
Il + indica concatenazione
10
• La classe String contiene numerosi metodi:
String s = saluto.substring(0,4) //s ha valore "Buon"
int n = saluto.length()
Linguaggi di Programmazione: Paradigmi di Programmazione
Linguaggi di Programmazione: Paradigmi di Programmazione
39
Stringhe
40
Uguaglianza di stringhe
• Le stringhe sono immutabili
restituisce true se le due stringhe
s e t sono uguali, false altrimenti
s.equals(t)
• Non ci sono metodi per cambiare un carattere in
una stringa: occorre creare una nuova stringa
String s = "salve";
String t = "salve";
dà true
s.equals(t)
String s = "salve";
se vogliamo sostituire la e con una a
String s = s.substring(0,4) + "a";
s == t
oppure
String s = "salva";
Linguaggi di Programmazione: Paradigmi di Programmazione
// n vale 10
41
non va bene usare l'operatore ==
darebbe false perché i valori di s e t
sono due oggetti diversi, anche se hanno
lo stesso valore
Linguaggi di Programmazione: Paradigmi di Programmazione
42
7
Variabili e metodi di classe
Variabili e metodi di classe
• E' possibile definire variabili (o metodi) associate
ad una classe, condivise da tutte le istanze di
quella classe
• In Java sono individuate dalla parola chiave static
cont2
numContatori
c
8
• Le variabili di classe sono visibili da tutte le istanze
della classe.
• Sono variabili globali (per tutte le istanze di una
classe).
Linguaggi di Programmazione: Paradigmi di Programmazione
43
Variabili e metodi di classe
Linguaggi di Programmazione: Paradigmi di Programmazione
44
Programmi in Java
• Una classe può essere considerata come un oggetto
(di tipo Class) che viene allocato staticamente
(all'inizio dell'esecuzione del programma)
• Le variabili ed i metodi di classe (static) sono
accessibili attraverso il nome della classe
int x,y;
Conta cont = new Conta(3);
cont.incr();
....
x = cont.c;
y = Conta.numContatori;
• Un programma in Java è una collezione di classi
• Una di queste deve contenere un metodo main
• L'esecuzione inizia dal main
• Il metodo main deve essere statico, perché
altrimenti bisognerebbe creare un oggetto della
classe Esempio prima di poterlo eseguire
class Esempio {
public static void main(String arg[]) {
System.out.println("questo è un esempio");
}
}
Linguaggi di Programmazione: Paradigmi di Programmazione
45
Esecuzione di programmi:
Interprete
Linguaggi di Programmazione: Paradigmi di Programmazione
46
Esecuzione di programmi:
Compilatore (traduttore)
LS = ling. sorgente
LM = ling. macchina
LS
c 5
2
class Conta {
static int numContatori = 0;
int c;
Conta(int i) {c = i;
++numContatori;}
void incr() {++c;}
void decr() {--c;}
int val() {return c;}
}
Progr.
sorgente
cont1
classe
Conta
Interprete
Progr.
sorgente
Compilatore
Progr.
oggetto
LS
LM1
LM2
LM
L'esecuzione mediante compilatore avviene in due fasi:
l'interprete esegue direttamente le
operazione del progr. sorgente
• traduzione da linguaggio sorgente a linguaggio macchina
• esecuzione del programma in linguaggio macchina
Linguaggi di Programmazione: Paradigmi di Programmazione
47
Linguaggi di Programmazione: Paradigmi di Programmazione
48
8
Esecuzione di programmi:
Soluzione Mista
Progr.
sorgente
Compilatore
Programma in ling.
intermedio
Interprete
JAVA
LM1
bytecode
LM2
Vantaggi
• Compilazione (Pascal, C, Ada, C++): Efficienza di
esecuzione. Il codice generato dal compilatore può
essere ottimizzato, perché la compilazione è fatta
una sola volta
• Interprete (JavaScript, Scheme, Prolog):
Interazione. Più facile modificare un programma
durante l'esecuzione
• Adottata da Java.
• Soluzione mista (Java): Portabilità. Per eseguire un
programma su macchine diverse è sufficiente
implementare l'interprete del linguaggio
intermedio, e non tutto il compilatore
• Il linguaggio intermedio si chiama bytecode.
Linguaggi di Programmazione: Paradigmi di Programmazione
49
Compilazione di un
programma in Java
Linguaggi di Programmazione: Paradigmi di Programmazione
50
Esecuzione di un
programma in Java
• Si crea un file <nome_file>.java contenente una o
più classi C1, C2, … e lo si compila.
• Si chiama l'interprete su una classe che contiene il
main (Es. C1)
> java C1
> javac <nome_file>.java
• L'interprete alloca questa classe e comincia ad
eseguire il main.
• Il compilatore crea un file .class in codice
intermedio (bytecode) per ogni classe contenuta
nel file .java:
C1.class, C2.class, ...
Linguaggi di Programmazione: Paradigmi di Programmazione
51
Un programma completo
class Contatore {
int c;
Contatore(int n) {c=n;}
void incr() {++c;}
void decr() {--c;}
int val() {return c;}
}
Linguaggi di Programmazione: Paradigmi di Programmazione
52
Compilazione in Java
• Una unità di compilazione è un file .java che
contiene delle definizioni di classi.
> javac <nome_file>.java
> java UsaCont
• Il compilatore produce un file .class per ogni classe
nel file.
class UsaCont {
public static void main(String arg[]) {
Contatore cont = new Contatore(5);
cont.incr();
System.out.println("valore =" + cont.val());
}
}
Linguaggi di Programmazione: Paradigmi di Programmazione
• Al massimo una di queste classi può essere public:
in questo caso deve avere lo stesso nome del file
(senza .java).
• L'interprete ha la responsabilità di caricare e
interpretare questi file.
53
Linguaggi di Programmazione: Paradigmi di Programmazione
54
9