• Non ci sono risultati.

Ogni oggetto ha un’interfaccia

N/A
N/A
Protected

Academic year: 2022

Condividi "Ogni oggetto ha un’interfaccia"

Copied!
95
0
0

Testo completo

(1)

Oggetti, classi, ereditarieta`

Corso di Programmazione ed Algoritmi Master di BioInformatica

Matteo Baldoni

Dipartimento di Informatica

Universita` degli Studi di Torino C.so Svizzera, 185 I-10149 Torino baldoni@di.unito.it

(2)

Chi sono? Come contattarmi?

Matteo Baldoni

Dipartimento di Informatica Università degli Studi di Torino Corso Svizzera, 185

I-10149 Torino (ITALY) e-mail: baldoni@di.unito.it

URL: http://www.di.unito.it/~baldoni Tel.: +39 011 670 67 56

Fax.: +39 011 75 16 03

“Sono nato a Torino nel 1968, nel febbraio 1993 mi sono laureato con lode in Scienze dell’Informazione e nel febbraio 1998 sono diventato Dottore in Ricerca in Informatica.

Dal luglio 1999 sono ricercatore in Informatica presso il Dipartimento di

(3)

Ogni oggetto ha un’interfaccia

e ogni oggetto ha un

tipo

(4)

Oggetti

Un oggetto rappresenta un dato, ed è costituito da

stato: collezione di variabili

comportamento: collezione di operazioni (metodi)

Esempio - contatore STATO

int c;

METODI

void iniz(int i) inizializza il contatore a i void incr() incrementa il contatore di 1 void decr() decrementa il contatore di 1

int val() restituisce il valore del

(5)

Incapsulamento

I dati e le procedure che li manipolano sono raggruppati in un’unica entità, l’oggetto.

Il mondo esterno ha accesso ai dati solo tramite un insieme di operazioni (metodi) che costituiscono

l’interfaccia dell’oggetto. I dettagli dell’implemen-tazione sono nascosti (INFORMATION HIDING)

(6)

Contatore

void iniz(int i) void incr()

void decr() int val()

INTERFACCIA IMPLEMENTAZIONE

CONTATORE

int c;

void iniz(int i) {c=1;}

void incr() {++c;}

void decr() {--c;}

int val() {return c;}

(7)

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.

Lo scambio di messaggi è l'unico modo di comunicare tra oggetti

Es.: esegui il metodo m1

(8)

Invio di Messaggi

finestra

0 esegui incr()

c

bottone 1

contatore invia valore di c

display

bottone 3

(9)

Invio di Messaggi

invio di messaggio = invocazione di un metodo

In Java, e altri linguaggi, si usa la notazione con il punto:

oggetto.metodo(…)

3

10 cont1

cont2

int x,y;

cont1.incr();

cont2.decr();

x = cont1.val();

y = cont2.val();

x ha valore 4 e y ha valore 9

(10)

Invio di Messaggi

In un linguaggio tradizionale, per eseguire una operazione su un dato, dovremmo passare il dato come parametro:

incr(cont1) o iniz(cont1, 3)

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)

(11)

Classi

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

Istanze

3 10

cont1 cont2

(12)

Classi (Java)

Una classe realizza l'implementazione di un tipo di dato astratto.

In Java:

class Contatore { int c;

void iniz(int i) {c = i;}

void incr() {++c;}

void decr() {--c;}

int val() {return c;}

(13)

Classi (Java)

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;}

(14)

Variabili private (Java)

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

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)

Tipi

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;

(16)

Tipi di dato primitivi (Java)

Java fornisce diversi tipi semplici primitivi.

A differenza di altri linguaggi, la dimensione dei tipi numerici è fissata per consentire la portabilità dei programmi:

byte 8 bit

short 16 bit

int 32 bit

long 64 bit

float 32 bit

double 64 bit

char 16 bit (Unicode)

(17)

Come si crea un’istanza

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)

(18)

Gestione della memoria

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

Un record di attivazione contiene le informazioni sul controllo (indirizzo di ritorno) ed i dati locali

Possibilità di chiamate ricorsive di procedure

(19)

Gestione della memoria

Codice

STATICA dati globali

STACK

record di attivaz.

dati locali

HEAP dati dinamici

(20)

Recupero della memoria

Garbage collection (Scheme, Prolog, Java)

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

(21)

Allocazione dinamica

Contatore cont1, cont2; cont1 cont2

(22)

Allocazione dinamica

Contatore cont1, cont2;

cont1 = new Contatore();

cont2 = new Contatore();

cont1.iniz(3);

cont2.iniz(10);

cont1 cont2

3

10

HEAP

(23)

Allocazione dinamica

Contatore cont1, cont2;

cont1 = new Contatore();

cont2 = new Contatore();

cont1.iniz(3);

cont2.iniz(10);

cont2 = cont1;

cont1 cont2

3

10

HEAP

Questo oggetto non è più accessibile.

Può essere recuperato dal garbage collector.

(24)

Puntatori (Java)

In Java non esistono puntatori espliciti 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)

(25)

Come si inizializza un oggetto

Si può chiamare esplicitamente un metodo di inizializzazione:

Contatore cont1;

cont1 = new Contatore();

cont1.iniz(3);

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.

(26)

Costruttori

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.

class Contatore { int c;

Contatore(int i) {c = i;}

void incr() {++c;}

void decr() {--c;}

int val() {return c;}

}

costruttore

(27)

Overloading di metodi (e costruttori)

Overloading: metodi diversi possono avere lo stesso nome.

I metodi "overloaded" si distinguono uno dall'altro in base alla lista dei tipi degli argomenti.

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;}

(28)

Il costruttore di “default” in Java

Se una classe non ha alcun

costruttore è presente un costruttore di “default” NomeDellaClasse() (che non esegue nessuna operazione particolare)

Se una classe ha invece un

qualsiasi costruttore il costruttore di

“default” non viene piu` aggiunto e quindi se lo si desidera deve essere esplicitamente aggiunto.

class Contatore { int c;

ContatoreContatore() () {}{}

void incr() {++c;}

void incr(int n) {c += n;}

void decr() {--c;}

int val() {return c;}

}

class Contatore { int c;

Contatore() {}

Contatore(int i) {c = i;}

void incr() {++c;}

void incr(int n) {c += n;}

(29)

I tipi semplici non sono oggetti (Java)

I tipi semplici, come ad es. gli interi, non vengono allocati dinamicamente nello heap, a differenza di altri linguaggi "puri"

come Smalltalk

Esistono classi wrapper che trasformano tipi semplici in oggetti

Contatore cont;

cont = new Contatore(3);

int x = 10;

cont x

3

HEAP

(30)

THIS

Come può un oggetto mandare un messaggio a se stesso, ossia invocare un proprio metodo?

Con la parola chiave this

class A { ...

void p() {...}

void m() { ... this.p(); ...}

}

si può anche scrivere solo p()

In alcuni casi this è indispensabile

(31)

THIS come costruttore

this da solo indica un costruttore della stessa classe

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)

(32)

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

class Conta {

static int numContatori = 0;

int c;

Conta(int i) {c = i;

++numContatori;}

void incr() {++c;}

void decr() {--c;}

(33)

Variabili e metodi di classe

Le variabili di classe sono visibili da tutte le istanze della classe.

Sono variabili globali (per tutte le istanze di una classe).

2

classe Conta

numContatori

8 c 5

c cont1

cont2

(34)

Variabili e metodi di classe

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;

(35)

Programmi in Java

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");

}

(36)

Compilazione di un programma in Java

Si crea un file <nome_file>.java contenente una o più classi C1, C2, … e lo si compila.

> javac <nome_file>.java

Il compilatore crea un file .class in codice intermedio (bytecode) per ogni classe contenuta nel file .java:

C1.class, C2.class, ...

(37)

Esecuzione di un programma in Java

Si chiama l'interprete su una classe che contiene il main (Es. C1)

> java C1

L'interprete alloca questa classe e comincia ad eseguire il main.

(38)

Un programma completo

class Contatore { int c;

Contatore(int n) {c=n;}

void incr() {++c;}

void decr() {--c;}

int val() {return c;}

}

class UsaCont {

public static void main(String arg[]) { Contatore cont = new Contatore(5);

cont.incr();

System.out.println("valore =" + cont.val());

} }

> javac <nome_file>.java

> java UsaCont

(39)

Compilazione in Java

Una unità di compilazione è un file .java che contiene delle definizioni di classi.

Al massimo una di queste classi può essere public: in questo caso deve avere lo stesso nome del file (senza .java).

Il compilatore produce un file .class per ogni classe nel file.

L'interprete ha la responsabilità di caricare e interpretare questi file.

(40)

Riuso del software:

Ereditarieta`, Composizione, Polimorfismo e

Binding Dinamico

(41)

Ereditarietà

Meccanismo per lo sviluppo incrementale di programmi

Consente di estendere classi preesistenti aggiungendo o modificando componenti (variabili o metodi)

(42)

Ereditarietà

Data la classe di sopra vogliamo estendere la finestra aggiungendo un titolo

class Finestra {

Rettangolo r; ....

void disegnaCornice() {...}

void disegnaContenuto() {...}

}

class FinestraConTitolo extends Finestra { String titolo;

void disegnaTitolo() {...}

(43)

Sottoclassi

FinestraConTitolo è una sottoclasse di Finestra.

Una sottoclasse eredita tutte le variabili ed i metodi della sopraclasse.

(44)

Ereditarietà

Gli oggetti della classe Finestra sono costituiti da

Gli oggetti della classe FinestraConTitolo sono costituiti da

variabili

Rettangolo r;

metodi

void disegnaCornice() {...}

void disegnaContenuto() {...}

variabili

Rettangolo r;

String titolo;

metodi

void disegnaCornice() {...}

(45)

Extends (Java)

E` la parola chiave per definire una gerarchia di classi

class ClassePadre { […]

}

class ClasseFigliaUno extends ClassePadre { […]

}

class ClasseFigliaDue extends ClassePadre { […]

ClassePadre

ClasseFigliaUno ClasseFigliaDue

Ereditarieta`

(46)

Extends (Java)

Superclasse, classe base, classe padre

Sottoclasse, classe derivata, classe figlia

Le sottoclasse hanno le funzionalita` delle proprie sopraclassi piu` altre specifiche

Specializzazione

Un elemento di una sottoclasse e` anche un elemento di una sua sopraclasse

class B extends A x ∈∈ B ⇒⇒ x ∈∈ A

A A B

(47)

Controllo statico dei tipi

Java, come molti altri linguaggi, effettua un controllo dei tipi (type checking) statico.

Statico: fatto dal compilatore prima di iniziare l'esecuzione del programma.

Dinamico: fatto dall'interprete durante l'esecuzione (a runtime)

Il type checking statico garantisce che non ci saranno errori durante l'esecuzione.

(48)

Controllo statico dei tipi

Type checking statico: il compilatore controlla che per una variabile si chiami un metodo definito per la classe di

Finestra f;

FinestraConTitolo ft;

...

ft.disegnaCornice();

f.disegnaCornice();

ft.disegnaTitolo();

f.disegnaTitolo();

errore di compilazione

f è una finestra e non ha il metodo disegnaTitolo

corretto

(49)

Tassonomie

Spesso l'ereditarietà è utilizzata per rappresentare tassonomie (classificazioni)

(50)

Sottotipi

Una sottoclasse può essere vista come l'implementazione di un sottotipo.

L'ereditarietà realizza una relazione is-a (è un).

Un rettangolo è un poligono.

Un rettangolo ha tutte le operazioni di poligono (eventualmente

(51)

Ereditarietà singola

Ogni sottoclasse ha una sola sopraclasse.

Struttura ad albero.

In Java la classe Object è la radice della gerarchia.

Qualunque oggetto è un Object.

I tipi primitivi non sono Object.

(52)

Ereditarietà multipla

In Java non è permessa.

Dà maggiore espressività ma crea problemi di conflitti e duplicazioni.

ApparecchioElettrico tensione

potenza

Articolo codice prezzo

Televisore pollici

(53)

Polimorfismo

POLIMORFISMO: proprietà di un oggetto di avere più di un tipo, in accordo alla relazione di

ereditarietà.

Esempio:

D sottoclasse di B e di A

un oggetto D è un B ed è un A

un oggetto di tipo (classe) D è

anche un oggetto di tipo (classe) B e anche un oggetto di tipo (classe) A

(54)

Polimorfismo

A a; B b; D d;

d = new D();

b = new D();

a = new D();

a = b;

questi

assegnamenti sono tutti legali perché un

oggetto di tipo D ha anche tipo B e A

(55)

Polimorfismo

L'assegnamento x = espr è legale per il compilatore se:

A uguale a B

B sottoclasse (sottotipo) di A

dove A è il tipo di x e B è il tipo di espr

Analogamente se x è un parametro formale di un metodo e espr è il parametro attuale (della chiamata)

Controllo statico.

(56)

Upcasting

Upcasting: ci si muove da un tipo specifico ad uno più generico (da un tipo ad un suo “sopratipo”).

L’upcasting è sicuro per il type checking: dato che una

sottoclasse eredita tutti i metodi delle sue sopraclassi, ogni messaggio che può essere inviato ad una sopraclasse può anche essere inviato alla sottoclasse senza il rischio di

A a; B b; D d;

d = new D();

b = d;

a = d;

d viene visto come se fosse un oggetto di tipo B d viene visto come se fosse un oggetto di tipo A

(57)

Upcasting

Poligono p;

Rettangolo r;

...

p.disegna();

r.disegna();

p.perimetro();

r.perimetro();

corretto per il compilatore

(58)

Upcasting

Poligono p;

Rettangolo r;

...

r.diagonale();

p.diagonale();

errore di

compilazione

p è di tipo Poligono e non ha il metodo diagonale

corretto

(59)

Upcasting

Poligono p;

Rettangolo r;

...

p = r;

r.diagonale();

p.diagonale();

Il compilatore dà errore ma, se si facesse il controllo a runtime, p.diagonale()

sarebbe corretto perché p è legata ad un rettangolo (che possiede il metodo

diagonale).

Visto da p, il rettangolo è un poligono.

p r

Rettangolo

(60)

Upcasting

Poligono p;

Rettangolo r;

p = r;

r.diagonale();

p.diagonale();

errore di

compilazione

p è di tipo Poligono e non ha il metodo diagonale

corretto

se si facesse il controllo a runtime,

sarebbe corretto perché p è legata ad un

(61)

Overriding

Una sottoclasse può anche ridefinire (OVERRIDING) un metodo della sopraclasse.

class Finestra {

Rettangolo r; ....

void disegnaCornice() {...}

void disegnaContenuto() {...}

}

class FinestraConTitolo extends Finestra { String titolo;

void disegnaCornice() { … disegna la cornice con il titolo …}

}

(62)

Cella (1)

class Cella {

int contenuto=0;

int get() {return contenuto;}

void set(int n) {contenuto=n;}

}

class CellaConMemoria extends Cella { int backup=0;

void set(int n) {backup=contenuto;

contenuto=n;}

void restore() {contenuto=backup;}

}

(63)

Ereditarietà da Object (Java)

class Complex { double re,im;

...

}

Complex c = new Complex(1.5, 2.4);

System.out.println(c);

c viene convertito in stringa con il metodo toString definito in Object.

Si ottiene: Complex@...

Si può ridefinite toString

class Complex { ...

String toString() {

return(re + " + i " + im);

} }

Con la stampa si ottiene:

1.5 + i 2.4

(64)

Come estendere un metodo

Spesso un metodo di una sottoclasse definito per

overriding non ridefinisce completamente il metodo con lo stesso nome della sua sopraclasse, ma lo estende.

Ad esempio, il metodo disegnaCornice della

FinestraConTitolo estende il metodo disegnaCornice della Finestra, con del codice specifico per disegnare il titolo.

Per evitare di duplicare il codice, si può far riferimento ad un metodo della sopraclasse con lo stesso nome mediante la notazione super.

(65)

super

Per ridefinire un metodo in modo incrementale:

class FinestraConTitolo extends Finestra { String titolo;

void disegnaCornice() { super.disegnaCornice();

... nuovo codice ...

} }

super.disegnaCornice() chiama il metodo

disegnaCornice della sopraclasse (che altrimenti non sarebbe visibile).

(66)

Cella (2)

class Cella {

int contenuto=0;

int get() {return contenuto;}

void set(int n) {contenuto=n;}

}

class CellaConMemoria extends Cella { int backup=0;

void set(int n) {backup=contenuto;

super.set(n);}

void restore() {contenuto=backup;}

}

(67)

Super come costruttore della sopraclasse

Super è utilizzata per chiamare un costruttore della sopraclasse

La chiamata di

this(… ) o super(…) deve essere la prima istruzione del

costruttore!

Se è omessa la chiamata di un costruttore sella sopraclasse viene sempre chiamato

class ClasseSopra {

public ClasseSopra(int x) {

System.out.println("Costruttore ClasseSopra: " + x);

}

public ClasseSopra() { this(-1);

System.out.println("Costruttore ClasseSopra");

} }

class ClasseSotto extends ClasseSopra { public ClasseSotto (int x) {

super(x);

System.out.println("Costruttore ClasseSotto");

}

public ClasseSotto() { super()super();;

System.out.println("ostruttore ClasseSotto");

}

(68)

Upcasting

Poligono p;

Rettangolo r;

...

p = r;

p.disegna();

p.perimetro();

corretto per il compilatore, ma

quale metodo si esegue?

Quello di Poligono o

(69)

Binding dinamico

Un oggetto decide quale metodo applicare a se stesso in base alla propria posizione nella gerarchia dell’ereditarieta`

Binding dinamico: decidere a tempo di esecuzione quale metodo applicare

Binding statico: decidere a tempo di compilazione quale funzione applicare (Pascal, C, …)

Java adotta il binding dinamico

(70)

Binding dinamico

p.perimetro();

Si esegue il metodo perimetro dell'oggetto a cui p fa riferimento in quel momento.

Poligono p = new Poligono();

Rettangolo r = new Rettangolo();

p.perimetro();

p = r;

p.perimetro();

si esegue il metodo perimetro di Poligono

si esegue il metodo

perimetro di Rettangolo

(71)

Binding dinamico

In questo contesto:

Binding: legame fra il nome di un metodo in una invocazione e (codice del) metodo.

obj.m(): quale metodo m viene eseguito?

Nei linguaggi tradizionali le chiamate di procedura vengono risolte dal compilatore.

Nei linguaggi ad oggetti (tranne il C++) le chiamate di metodi sono risolte dinamicamente.

BINDING DINAMICO: la forma di un oggetto determina dinamicamente quale versione di un metodo applicare.

(72)

Binding dinamico

class Finestra {

Rettangolo r; ....

void disegnaCornice() {...}

void disegnaContenuto() {...}

void rinfresca() {

this.disegnaCornice();

this.disegnaContenuto();

} }

class FinestraConTitolo extends Finestra { String titolo;

void disegnaCornice() { … disegna la cornice con il titolo …}

(73)

Binding dinamico

void rinfresca() {

this.disegnaCornice();

this.disegnaContenuto();

}

this (che può anche essere omesso) si riferisce sempre all’oggetto corrente.

FinestraConTitolo ft;

...

ft.rinfresca();

chiama il metodo disegnaCornice di FinestraConTitolo

(74)

Overriding

Ricerca di un metodo per un oggetto:

la sottoclasse verifica se possiede o meno un metodo con tale nome e con gli stessi parametri (stessa signature), se si`, lo usa

se no, la classe padre cerca per la classe figlia tale metodo tra quelli in essa definiti (e cosi` via nella gerarchia)

Un metodo definito in una sottoclasse e avente la stessa signature di un metodo di una delle classi antenate

nasconde il metodo di quest’ultima alla sottoclasse

(75)

Overloading, overriding, …

Firma o

signature: nome + lista dei tipi dei parametri

Overloading:

stesso nome ma diversa lista dei tipi di parametri

Overriding:

stessa firma ma classi diverse (purché nella stessa

gerarchia)

class ClasseA {

public void metodo (int x) {

System.out.println("Metodo di Classe A: " + x);

}

public void metodo() {

System.out.println("Metodo di Classe A");

this.metodo(-1);

} }

class ClasseB extends ClasseA { public void metodo (int x) {

System.out.println("Metodo di Classe B esteso");

super.metodo(x);

}

public void metodo() {

System.out.println("Metodo di Classe B esteso");

super.metodo();

}

OVERLOADING

OVERLOADING OVERRIDING OVERLOADING

(76)

Overriding di metodi privati

Se invio il messaggio metodo1 ad un oggetto di tipo ClasseDue quale metodo metodo2 viene eseguito?

Binding dinamico?

Dichiarare che un metodo è privato equivale a “cambiargli nome”

In effetti a parte ClasseUno nessuno sa o deve sapere dell’esistenza di metodo2 di

class ClasseUno {

public void metodo1 () {

System.out.println("Eseguito metodo 1 nella classe Uno");

this.metodo2();

}

private void metodo2() {

System.out.println("Eseguito metodo 2 nella classe Uno");

} }

class ClasseDue extends ClasseUno { public void metodo2 () {

System.out.println("Eseguito metodo 2 nella classe Due");

}

(77)

Overriding di campi

È possibile ridefinire dei campi

MA

Ai campi non si applica il binding dinamico!

class ClassePadre { public int x = 1;

public int y = 2;

public void getValue() {

System.out.println("Valore della x: "

+ this.x);

System.out.println("Valore della y: ” + this.y);

} }

class ClasseFiglia extends ClassePadre { public String x = “3”;

public int z = 4;

public void getValue() { super.getValue();

System.out.println("Valore della x estesa: " + this.x);

System.out.println("Valore della z: ” + this.z);

(78)

Overriding di variabili nei blocchi

È possibile definire variabili locali ad un blocco

MA

A differenza del C o del

Pascal, in un blocco interno Java non è possibile ridefinire una variabile esterna

class ProvaVariabiliLocali {

public static void main(String[] args) {

{

int z = 2;

}

System.out.println(z);

int x = 1;

if (x > 0) {

int y = 3;

} else {

int x = 2;

int y = 5;

}

(79)

Riuso del software

La programmazione ad oggetti consente di utilizzare classi già esistenti per produrre nuovo software:

Uso.

Un oggetto comunica con oggetti di altre classi

Composizione.

Si definiscono nuove classi i cui oggetti sono composti di oggetti di classi già esistenti.

Ereditarietà.

Favorisce lo sviluppo incrementale, estendendo classi già esistenti.

(80)

Composizione

class Automobile { int lunghezza;

Motore motore;

Ruota[] ruote;

...

}

class Motore {

int cilindrata;

...

}

Automobile miaAuto = new Automobile();

...

class Ruota {

double pressione;

int diametro;

...

}

(81)

Ereditarietà vs composizione

AppElettr Articolo

Televisore

Televisore è un apparecchio elettrico e è un articolo.

La sottoclasse eredita il

comportamento di altre classi.

Automobile

Motore Ruote

Carrozzeria

L'automobile ha un motore, una carrozzeria, …

L'automobile non ha il

comportamento del motore, ...

(82)

Programmare con        l'ereditarietà

Si consideri una figura composta di diverse forme geometriche (linee, rettangoli, cerchi, …).

Nella programmazione

tradizionale, una procedura per disegnare la figura dovrebbe considerare tutti i casi.

Se si aggiunge la forma

TRIANGOLO occorre modificare la procedura disegna.

void disegna(figura f) { for ogni forma S in f switch(S.genere) case LINEA:

disegnaLinea() case RETTANGOLO:

disegnaRettangolo() case CERCHIO:

disegnaCerchio()

}

(83)

Programmare con        l'ereditarietà

class Figura {

Forma[] s; //una figura è inplementata //come un array di Forme

void disegnaFigura() {

for (int i=0; i<s.length; i++) s[i].disegna();

(84)

Programmare con        l'ereditarietà

Se si aggiunge la forma Triangolo, è sufficiente definire una nuova sottoclasse di Forma con il metodo disegna:

La classe Figura non viene modificata.

Il binding dinamico fa sì che, se la figura contiene un triangolo, venga chiamato il metodo per disegnare un triangolo.

class Triangolo extends Forma { ...

void disegna(){...} }

(85)

Classi astratte

In un programma non ci si aspetta di chiamare il metodo disegna della classe Forma, né di usare oggetti di questa classe.

La classe Forma serve solo per avere una interfaccia comune per le varie forme specifiche.

(86)

Classi astratte

abstract class Forma {

abstract void disegna();

}

class Linea extends Forma { void disegna() { ...}

}

....

Forma f = new Forma();

Forma f = new Linea();

Errore di compilazione.

Non si possono creare og- getti di una classe astratta.

Non c'è la implementa- zione del metodo

Alcuni metodi (dichiarati abstract) non sono implementati

(87)

Es.: Poligoni

perimetro, area sono piu` volte ridefinite nella gerarchia di classe

(88)

Es.: Prisma

I metodi volume, superficieLaterale e SuperficieTotale sono polimorfi

(89)

Interfacce

Una classe astratta pura costituisce una interfaccia.

In Java può essere definita anche come interface.

interface Forma { void disegna();

}

class Linea implements Forma { void disegna() { ...}

} ...

Forma f = new Linea();

(90)

Interfacce vs. classi astratte

Le classi astratte possono essere miste, ossia possono contenere anche metodi non astratti.

Con l'ereditarietà singola di Java, una classe può essere sottoclasse solo di una classe astratta.

Le interfacce invece non sono soggette al vincolo della struttura gerarchica ad albero.

Una classe può implementare più di una interfaccia (qualche analogia con ereditarietà multipla).

(91)

Interfacce multiple

interface A {

void metodoA();

}

interface B {

void metodoB();

}

class C implements A,B {

void metodoA() {System.out.println("sono A");}

void metodoB() {System.out.println("sono B");}

public static void main(String[] args) {

A a = new C();//l’oggetto è visto come un A B b = new C();//l’oggetto è visto come un B a.metodoA();

b.metodoB();

(92)

Classi generiche

La proprietà che tutte le classi sono discendenti di Object

consente di definire strutture dati che possono contenere oggetti di qualunque tipo.

Non si può specificare il tipo degli elementi della pila:

possono essere oggetti qualunque.

class Pila { ...

void push(Object x) {...};

Object pop() {...};

}

Pila s; Linea l; Rettangolo r;

...

s.push(l); s.push(r);

(93)

Downcasting

Supponiamo di sapere che sulla pila vengono messi solo rettangoli. Come possiamo utilizzare gli oggetti estratti dalla pila?

class Pila { ...

void push(Object x) {...};

Object pop() {...};

}

Pila s; Rettangolo r;

...

s.push(new Rettangolo());

r = s.pop(); Errore di compilazione.

pop restituisce un Object, che è più generale di Rettangolo

(94)

Downcasting

Downcasting: ci si muove da un tipo più generale ad uno più specifico (da un tipo ad un sottotipo)

Se A è un sottotipo di B e se espr ha tipo B, (A) espr ha tipo A

L’assegnamento

A a = (A) espr è corretto per il compilatore

(A) espr può dare errore a run time, se l’oggetto ottenuto valutando espr non ha tipo A.

(95)

Downcasting

class Pila { ...

void push(Object x) {...};

Object pop() {...};

} ...

Pila s; Rettangolo r;

...

s.push(new Rettangolo());

r = (Rettangolo) s.pop();

Accettato dal compilatore.

Può dare errore a run time.

Controllo a run-time.

Quando si esegue questa istruzione

si controlla che l'oggetto restituito

da pop sia veramente un rettangolo.

Non e` un cast alla “C” !

Riferimenti

Documenti correlati

Una serie temporale si può pensare come una realizzazione di un processo stocastico (limitata ad un tempo finito).. Esempio: white noise a

La colpoisterectomia con colpo- cleisi parziale o totale è una procedura chirurgica rac- comandata per ridurre i sintomi del prolasso genitale nelle donne avanti negli anni che

With the construction of this southern property wall, several small rooms were built along the Via Stabiana immediately inside the Porta Stabia (fig.. The actual function of

Papa, La tipicita` iconografica della fattispecie e l’interpretazione del giudice. La tradizione illuministica e le sfide del presente, in Principi, regole, interpretazione. scritti

La domanda quindi è questa: allora questo processo di globalizzazione final- mente fa si che i neri degli Stati Uniti possano essere considerati tutti cittadini, come gli

Le pubbliche relazioni con le Aziende Sponsor, lo Staff della Nazionale e tutte le figure della Federazione Italiana di Rugby vengono coltivate anche durante le cene di

Quale deve essere la minima velocità con cui di deve lanciare un oggetto di massa 1 kg dalla supercie della Terra, anché possa sfuggire all'attrazione gravitazionale terrestre

Indicare l’indirizzo del 1° e dell’ultimo host della 10° subnet relativa all’indirizzo di rete 25.0.0.0 di cui 13 bit sono dedicati agli host e i rimanenti alle subnet.