Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack •...

23
1 Stampare una Pila Stampare una Pila Quando si stampa un Pila gli elementi appaiono nell’ordine inverso a quello di inserimento; inoltre la Pila si vuota. Supponiamo di avere introdotto nella Pila i valori 1, 2, 3 nell’ordine; per stampare la Pila bisogna accedere ad ogni elemento e poiché è accessibile solo la testa, per poter “vedere” gli altri elementi si deve togliere la testa. La testa è l’ultimo elemento inserito e perciò gli elementi appaiono in ordine inverso. Stampare una Pila 1 3 2 stampa testa stampa testa stampa testa 3 2 1 Pila vuota Se vogliamo stampare gli elementi nello stesso ordine di inserimento, dobbiamo prendere un’altra Pila e “rovesciare” quella iniziale e stampare la nuova Pila. 1 1 2 Stampare una Pila 1 3 2 1 1 2 3 3 2 3 2 1

Transcript of Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack •...

Page 1: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

1

Stampare una Pila

Stampare una Pila• Quando si stampa un Pila gli elementi

appaiono nell’ordine inverso a quello di inserimento; inoltre la Pila si vuota.

• Supponiamo di avere introdotto nella Pila i valori 1, 2, 3 nell’ordine; per stampare la Pila bisogna accedere ad ogni elemento e poiché èaccessibile solo la testa, per poter “vedere” gli altri elementi si deve togliere la testa. La testa è l’ultimo elemento inserito e perciò gli elementi appaiono in ordine inverso.

Stampare una Pila

1

3

2

stampa testa stampa testa stampa testa3 2 1

Pila vuota

• Se vogliamo stampare gli elementi nello stesso ordine di inserimento, dobbiamo prendere un’altra Pila e “rovesciare” quella iniziale e stampare la nuova Pila.

1 1

2

Stampare una Pila

1

3

2

1

1

2

3

3

2

3

2

1

Page 2: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

2

Pila o Stack• Analogamente se vogliamo eseguire la ricerca

di un elemento in una Pila: non ci sono assiomi di “ricerca elemento” tra gli assiomi dello Stack.

• È necessario quindi utilizzare una Pila di appoggio, estrarre gli elementi dalla Pila in cui eseguire la ricerca. Se la testa coincide con l’elemento cercato allora l’elemento èpresente. Se la Pila iniziale si vuota l’elemento non è presente. Successivamente si inseriscono nella Pila iniziale gli elementi tolti.

Pila o Stack• Esercizio. Si consideri una formula

matematica; scrivere un algoritmo per verificare se le parentesi sono o no bilanciate.

• Analisi del problema.• La formula

{a + (b-c) * [(a + b) - 7]}ha parentesi bilanciate, mentre la formula

{a + (b-c}-5) non ha parentesi bilanciate, anche se il numero di tonde e graffe aperte coincide con il numero di quelle chiuse. Quindi non è sufficiente contarle.

Pila o Stack• I soluzione.• Consideriamo un array di caratteri in cui

memorizzare le parentesi. Si esamina la formula un carattere alla volta e si inseriscono le parentesi (aperte) nell’array.

• Quando si incontra una parentesi chiusa si verifica se l’ultima parentesi è la sua corrispondente aperta.

• In questo caso si toglie dall’array la parentesi aperta e si prosegue, esaminando il successivo carattere della formula.

Pila o Stack• Se alla fine della scansione della formula

l’array è vuoto, allora la formula ha parentesi bilanciate.

• Se si incontra una parentesi che non corrisponde oppure se non si vuota l’array, significa che le parentesi non sono bilanciate (vd. Soluzionilab7).

• Si vede che la gestione dell’array è fatta con un indice che cresce quando si inseriscono le parentesi e cala quando si tolgono.

Page 3: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

3

Pila o Stack• Osservando gli inserimenti e le cancellazioni

delle parentesi, si vede che si tratta della gestione di una Pila.

• II soluzione.• Consideriamo le due stringhe

String aperte = "{[(";

String chiuse = "}])";

Invece di memorizzare caratteri (le parentesi) memorizziamo gli indici 0, 1, 2 dei caratteri delle due stringhe e consideriamo una Pila di interi.

Pila o Stack• Consideriamo un carattere della formula e

vediamo se è un carattere della stringa aperte.

• Se risulta:aperte.indexof(carattere) ≠≠≠≠ -1

si tratta di una parentesi aperta: possiamo memorizzare il numero corrispondente al valore aperte.indexof(carattere) nella Pila (e sarà uno di questi: 0, 1, 2).

Pila o Stack• Se invece risulta:

aperte.indexof(carattere) ==== -1

• allora il carattere esaminato non è una parentesi aperta, ma sarà un altro carattere oppure una parentesi chiusa.

• Esaminiamo allora le parentesi chiuse. Se risulta:

chiuse.indexof(carattere) ≠≠≠≠ -1

allora il carattere è una parentesi chiusa.

Pila o Stack• Guardiamo la testa della Pila: se la testa della

Pila ha memorizzato un numero che corrisponde al valore

chiuse.indexof(carattere)

significa che è memorizzata “la parentesi aperta” corrispondente e pertanto si estrae la testa.

• Se non coincide la formula è errata.• Se lo Stack si vuota allora le parentesi sono

bilanciate.

Page 4: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

4

Controllo di accesso

Controllo di accesso

• Nel linguaggio Java l’accesso a variabili, metodi e classi può essere (Par. 10.7):• public• private• protected• di pacchetto (nessuna specifica)

• public significa che l’accesso è possibile da tutte le classi;

• private significa che l’accesso è possibile solo all’interno della classe;

Controllo di accesso

• protected significa che l’accesso è possibile dalla classe e da tutte le sottoclassi, ed anche dalle classi dello stesso pacchetto (Arg. Avanzati 10.3);

• di pacchetto significa che l’accesso è possibile all’interno dello stesso pacchetto.

• Come pacchetto possiamo considerare la directory nella quale si trovano le classi: la classe di prova e altre classi. È una specifica buona per classi e metodi ma non per le variabili di istanza che è bene che siano sempre private.

Controllo di accesso

• In un pacchetto si inseriscono classi aventi la medesima funzionalità. La prima riga del file che contiene la classe deve iniziare con l’istruzione:

package nomePacchetto;• Per utilizzare una classe di un pacchetto si può

scrivere:nomePacchetto.nomeClasse

• oppureimport nomePacchetto.nomeClasse;

• Noi non tratteremo la costruzione di pacchetti, ma sarà bene costruire delle cartelle con le classi che risolvono o gestiscono un particolare problema.

Page 5: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

5

Variabili statiche o di classe

Variabili statiche o di classe

• Si può avere bisogno di utilizzare una variabile che non sia di un esemplare della classe ma che possa essere condivisa da tutti gli esemplari della classe.

• Esempio. Supponiamo di voler numerare in maniera progressiva i conti correnti in modo tale che ogni correntista abbia un numero di conto diverso; tale numero viene incrementato di uno per ogni nuovo conto attivato: – il primo correntista ha il numero 1, il secondo il

numero 2, ecc.

Variabili statiche o di classe

• Modifichiamo la classe BankAccount. Questa nuova variabile, numeroConto, rappresenta il numero di correntisti e il suo valore èl’ultimo numero assegnato. Possiamo pensare di fare la seguente modifica:

public class BankAccount{

private int ultimoNumero;

private int numeroConto;

public BankAccount(){

ultimoNumero++;

numeroConto = ultimoNumero;

} . . . }

Variabili statiche o di classe

• Questo costruttore, però, non funziona perchéla variabile ultimoNumero è una variabile di esemplare: ne esiste una copia per ogni oggetto; il risultato è che tutti i conti creati hanno il numero di conto uguale a 1.

• Ci servirebbe una variabile condivisa da tutti gli oggetti della classe. Una variabile con questa semantica si ottiene con la dichiarazione static:private static int ultimoNumero=0;

Page 6: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

6

Variabili statiche o di classe

• Una variabile static, detta anche variabile di classe, è condivisa da tutti gli oggetti della classe. Di essa ne esiste un’unica copia, ed èper questo che può incrementarsi effettivamente.

• Questa variabile è memorizzata al di fuori degli oggetti BA.

• Ogni metodo e costruttore della classe può accedere a questa variabile e modificarla.

Variabili statiche o di classe

• Per inizializzare una variabile statica non si può utilizzare una istruzione del costruttore, altrimenti il suo valore verrebbe inizializzatoogni volta che si costruisce un nuovo oggetto (e non sarebbe più condivisa).

• Pertanto si deve inizializzarla esplicitamente:private static int ultimoNumero=0;

• oppure utilizzare l’inizializzazione di default.• L’inizializzazione avviene una sola volta

quando la classe viene attivata.

Variabili statiche o di classe

• Nella programmazione ad oggetti, l’utilizzo di variabili statiche deve essere limitato: infatti i metodi che usano variabili statiche hanno un comportamento che non dipende soltanto dai loro parametri, impliciti ed espliciti.

• Le variabili statiche devono essere private, per evitare accessi non controllati.

Variabili statiche o di classe

• È invece comune usare costanti statiche, come nella classe Math:public static final double PI =

3.14159265358979323846;

• Tali costanti sono di norma public e per ottenere il loro valore si usa il nome della classe seguito dal punto e dal nome della costante: Math.PI .

Page 7: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

7

Vettori

Vettori

• In Java esistono classi per realizzare strutture di dati sequenziali con dimensione variabile, chiamate vettori. La classe ArrayList nella nuova versione permette di aggiungere alla definizione il tipo di dato di cui si vuole costruire il vettore (par. 7.2).

• La classe prevede metodi per operazioni di inserimento, rimozione, accesso, ecc.

• Sintassi.ArrayList<tipoClasse> nomeoggetto =

new ArrayList<tipoClasse>();

Vettori• Metodi:

• add(elemento): aggiunge alla fine della sequenza un elemento di tipo <tipoClasse>

• add(i, elemento): inserisce un elemento nella posizione i

• get(i): restituisce l’elemento nella posizione i• remove(i): toglie l’elemento nella posizione i• set(i, nuovoelem): sostituisce nuovoelem nella

posizione i• size(): restituisce la dimensione del vettore.

• Per eseguire la ricerca di un elemento si effettua una scansione della struttura.

Vettori

• Le parentesi < … > indicano che tipoClasse èun tipo parametrico, vale a dire che si può inserire il nome di una classe che rappresenta un tipo qualunque di dato; per questo motivo la classe ArrayList viene anche detta “classe generica”.

• Costruiremo un array di oggetti di tipo BA e un vettore ArrayList di oggetti di tipo BA (vd. Laboratorio 7).

Page 8: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

8

Classi involucro

Classi involucro

• La classe ArrayList accetta solo tipi di dato che rappresentano oggetti. Se vogliamo utilizzare ArrayList per gestire un tipo base come si può fare?

• Il linguaggio permette di “trasformare”l’elemento del tipo base in un oggetto della classe corrispondente. Queste classi si chiamano: classi involucro.

• Esistono classi involucro per ognuno dei tipibase: Byte, Short, Integer, Long, Float, Double, Character, Boolean.

Classi involucro

• Un esemplare di una classe involucro contiene un elemento del suo tipo base corrispondente.

• Per costruire un esemplare della classe involucro, nelle versioni precedenti si doveva esplicitamente eseguire la creazione dell’oggetto:

Double d = new Double(3.5);

nella versione attuale si scrive:Double d = 3.5;

Classi involucro

• Per effettuare il viceversa, recuperare dall’oggetto il suo contenuto, nella versione precedente si doveva scrivere:

double x = d.doubleValue();

ora si scrive semplicemente:double x = d;

• L’occupazione di spazio di x e d è diversa: x èuno scalare, d è un oggetto (un riferimento piùl’area per l’oggetto).

Page 9: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

9

Classi involucro

Stack Heap

x

d

3.5 3.5

Classi involucro

• Se si volesse costruire un vettore di numeri reali si dovrebbe scrivere:ArrayList<Double> vettore =

new ArrayList<Double>;

• Per assegnare i valori all’oggetto vettore di tipo ArrayList si avrà:

vettore.add(3.5);

• Per conoscere il valore presente nella posizione i

double x = vettore.get(i);

Classi involucro

• Questa tenica di auto-impacchettamento (detta auto-boxing) non sempre propone conversioni “ovvie”; l’assegnazione:

Double oggetto = 2.0;

è corretta, mentre non lo è:Double oggetto = 2; //errato

perché viene interpretata dal compilatore come:

Double oggetto =

new Integer(2);//errato

Classi involucro

• Altre conversioni, invece, sono possibili anche se “strane”; si possono ad esempio effettuare le seguenti operazioni aritmetiche:

Double elem;

elem = d+1;

• converte automaticamente d al suo valore numerico (3.5), aggiunge +1, inserisce il valore ottenuto nell’involucro elem.

• Se non è strettamente necessario, è meglio non usare le classi involucro, ma i tipi base.

Page 10: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

10

Interfacce

Interfacce

• Vogliamo rappresentare una proprietàastratta, per esempio un TDA, senza preoccuparci della sua implementazione.

• Il linguaggio Java mette a disposizione il concetto di interfaccia.

• Tramite le interfacce è anche possibile effettuare il riutilizzo del codice. (Capitolo 9)

Interfacce

• Abbiamo detto che uno Stack è un contenitore di informazioni per il quale valgono le seguenti operazioni:• isEmpty : verifica di contenitore vuoto• top : visione del primo elemento (testa)• push : inserimento di un elemento in testa• pop : estrazione della testa

• Abbiamo detto che lo Stack si può realizzare mediante:• array• lista concatenata

Interfacce

• Le due realizzazioni dello Stack svolgono gli stessi compiti.

• Vogliamo trovare il modo per poter dichiarare quali sono le operazioni del TDA, senza pensare alla scelta della struttura di dati con la quale si costruirà lo Stack.

• Definiamo il TDA in una interfaccia, dicendo cosa fa.

• Realizziamo il TDA in una classe, dicendo come si fa.

Page 11: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

11

Interfacce

• Sintassi.public interface NomeInterfaccia{

firma dei metodi}

public class NomeClasse implementsNomeInterfaccia{

metodi dell’interfaccia: codice relativo all’implementazione scelta

}

Interfacce

• Esempio.• Definizione dell’interfaccia Stack:public interface Stack{

boolean isEmpty();

void push(Object elem);

void pop();

Oject top();

}

//si può anche definire

//Object pop();

//in questo caso restituisce il valore della

// testa

Interfacce

• Costruzione dello Stack:public class StackArray

implements Stack{

//codice relativo ad uno Stack con

//array

}

public class StackListC

implements Stack{

//codice relativo ad uno Stack con

//lista concatenata

}

Interfacce

• Realizzazione dello Stack

interfaccia Stack

classi StackArray StackListC

Page 12: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

12

Interfacce

• L’interfaccia è definita con accesso public, perché per sua natura deve poter essere implementata da una classe qualunque.

• I suoi metodi sono automaticamente public(default).

• Quando si realizza in una classe un metodo di un’interfaccia, questo deve essere definito public.

Interfacce

• Differenze tra classe e interfaccia.• Un’interfaccia:

• non ha variabili di istanza• non ha costruttori• tutti i suoi metodi sono astratti: del metodo

c’è solo la firma, non c’è codice• tutti i metodi sono automaticamente

pubblici.

Interfacce

Una classe può estendere una sola altra classe

superclasse

sottoclasse

Interfacce

• Una classe può realizzare più interfacce. • Ogni interfaccia realizza una proprietà e una

classe può voler realizzare varie proprietàdiverse tra loro.

• Vediamo di costruire una classe StackArrayche realizza (implements) l’interfaccia Stack.

• La classe StackArray utilizza un arrayridimensionabile di oggetti.

• Dovremo considerare l’eccezione “Stackvuoto” per i metodi pop e top.

Page 13: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

13

Interfaccia Stack e classe StackArray

public class StackArray implements Stack{

private Object vett[]; //array

private int sp ; //stack pointer

public StackArray(){ //costruttore

vett = new Object[2];

sp = 0; }

/** assiomi dello Stack: isEmpty, push, pop, top */

public boolean isEmpty() {

/** verifica di lista vuota: O(1) */

if (sp==0)

return true;

else return false;

}

Interfaccia Stack e classe StackArray

public void push(Object elem) {

/**inserimento in testa: in media O(1)*/

if ( sp==vett.length )

raddoppio();

vett[sp] = elem;

sp++; }

public void pop() {

/**estrae il primo: O(1) */

if ( sp > 0 ) // if (!isEmpty())

sp--;

else throw new EmptyStackException("\nStack vuoto: sp = "

+ sp + "\nnon si puo' eseguire pop ");

}

Interfaccia Stack e classe StackArray

public Object top(){

/**visione della testa: O(1)*/

if (isEmpty())

throw new EmptyStackException

("\nStack vuoto: sp = "

+ sp + "\nnon si puo' eseguire top ");

else

return vett[sp-1];

}

/** metodi accessori allo stack */

Interfaccia Stack e classe StackArray

/** restituisce la testa e la toglie */

public Object topAndPop(){//Object pop()

. . . }

private void raddoppio() {

//raddoppio di vett

. . . }

//sovrascrive toString()

public String toString(){

return "nello Stack ci sono " +

sp +" elementi";

}

}//fine classe StackArray

Page 14: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

14

Costruire un’eccezione

• Costruiamo l’eccezione per gestire la situazione “Stack vuoto”:

EmptyStackException

• Per costruire una nuova eccezione dobbiamo fare due scelte.

• I scelta. Stabilire se l’eccezione estenderà le RuntimeException oppure estenderà Exception.

• II scelta. Vogliamo utilizzare i costruttori dell’eccezione o gestire un messaggio personale che spieghi il lancio dell’eccezione.

Costruire un’eccezione

• I scelta.• Le eccezioni che estendono le

RuntimeException non sono a controllo obbligatorio.

• Le eccezioni che estendono Exception sono a controllo obbligatorio e pertanto in tutti i metodi che sono coinvolti nel lancio di un’eccezione si deve scrivere nella firma:

throws EmptyStackException

I metodi sono: pop, top, topAndPop, main.

Costruire un’eccezione

• II scelta.

• Utilizziamo costruttori e metodi di Exception:public class EmptyStackException

extends Exception {

//corpo vuoto

}

• Con questa scelta la classe solamente eredita il comportamento (metodi e costruttori) di Exception: abbiamo solo dato un nostro nome che ricorda il tipo di problema.

Costruire un’eccezione

• Nel nostro esempio la classe EmptyStackException estende le eccezioni RuntimeException, dato che nell’intestazione non c’èthrows; inoltre abbiamo potuto inserire un messaggio in cui visualizzare il valore di sp.

• Solitamente in una classe che costruisce un’eccezione si hanno due costruttori:• uno senza parametri• uno con parametro di tipo stringa che richiama il

costruttore della superclasse

Page 15: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

15

Costruire un’eccezione

public class EmptyStackException extendsRuntimeException {

//costruttori

public EmptyStackException(){//primo

//corpo vuoto

}

public EmptyStackException

(String messaggio){//secondo

super(messaggio);

//richiama il metodo getMessage

//della classe RuntimeException

}

}

Realizzare Stack

• Per vedere la realizzazione dell’interfaccia Stackcostruiamo una classe di prova per la classe StackArray.

• Possiamo definire due oggetti:1) StackArray stA =

new StackArray();

è la solita costruzione di un oggetto di tipo NomeClasse2) Stack st = new StackArray();

abbiamo una conversione di tipo tra classe e interfaccia (Par. 9.2).

Realizzare Stack

• Nel secondo caso l’operatore new costruisce un oggetto di tipo StackArray che è una classe che implementa l’interfaccia Stack e restituisce un riferimento a un oggetto di quel tipo, che può essere assegnato a st solo perché StackArrayimplementa Stack (altrimenti il compilatore segnalerebbe errore).

• Tramite il riferimento st possiamo usare tutti i metodi dell’interfaccia Stack; non possiamo usare topAndPop che è solo della classe StackArray.

Realizzare Stack

• Per capire la potenza della definizione di TDA come interfaccia, supponiamo che qualcuno abbia progettato la seguente classe:public class StackX implements

Stack{

...

}

• Anche senza sapere come sia realizzata StackX, possiamo usarne un esemplare mediante il suo comportamento astratto definito in Stack.

Page 16: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

16

Realizzare Stack

• Possiamo quindi usare un esemplareattraverso i suoi metodi: isEmpty, top, pop, push.

• Analogamente possiamo usare un esemplare di qualsiasi altra classe, StackY, che realizza Stack.

• Vediamo con un esempio. Costruiamo una classe di prova che costruisce uno Stackinserendo oggetti di tipo stringa e poi stampiamo lo Stack.

Realizzare Stack

• Nella classe di prova possiamo scrivere:Stack s = new StackX();

s.push("Pippo");

s.push("Pluto");

s.push("Paperino");

//stampa dello Stack

while(!s.isEmpty()){

System.out.println(s.top());

s.pop();

}

• ottenendo la costruzione dello Stack, la sua stampa e lo svuotamento dello Stack.

Conversioni di tipo fra sottoclasse e

superclasse

Conversioni di tipo fra sottoclasse e superclasse

• Abbiamo costruito una classe SavingsAccountcome sottoclasse di BankAccount.

• Può esserci la necessità di memorizzare un riferimento di una sottoclasse in un riferimento a superclasse: è quello che abbiamo fatto nell’esempio precedente dove push ha come parametro un elemento di tipo Object e abbiamo passato una stringa per costruire lo Stack.

Page 17: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

17

Conversioni di tipo fra sottoclasse e superclasse

• È possibile memorizzare un riferimento a un oggetto di tipo SavingsAccount in un riferimento di tipo BankAccount che è una superclasse.

• Analogamente è possibile memorizzare un qualsiasi riferimento a oggetto in un riferimento di tipo Object che è la superclasse universale.

• La conversione di tipo è automatica (Par.10.5).

Conversioni di tipo fra sottoclasse e superclasse

• Consideriamo questi riferimenti:

SavingsAccount sA =

new SavingsAccount(2);

BankSAccount bA = sA;

Object oA = sA;

• Abbiamo tre riferimenti diversi che vedono la stessa area di memoria.

Conversioni di tipo fra sottoclasse e superclasse

sA

bA oA

balance 0

interestRate 2

Conversioni di tipo fra sottoclasse e superclasse

• Ogni riferimento può usare solo i metodi della sua classe:

bA.deposit(500);

bA può modificare il saldo, però non può usare addInterest.

• Con il riferimento oA (di Object) si possono usare solo i metodi di Object (toString, equals, e pochi altri).

• Ciò nonostante può essere utile usare un riferimento della superclasse.

Page 18: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

18

Conversioni di tipo fra sottoclasse e superclasse

• Aggiungiamo a BankAccount il seguente metodo che permette di trasferire denaro da un conto ad un altro:public class BankAccount{

. . .

public void transferTo

(BankAccount other, double amount){

this.withdraw(amount);

other.deposit(amount);

}

}//fine BA

Conversioni di tipo fra sottoclasse e superclasse

• Esempio.BankAccount padre =

new BankAccount(5000);

BankAccount figlio =

new BankAccount();

padre.transferTo(figlio, 300);

• Controlliamo con una stampa il saldo di entrambi:

Conversioni di tipo fra sottoclasse e superclasse

System.out.println

(padre.getBalance());//4700

System.out.println

(figlio.getBalance());//300

• Con l’invocazione del metodopadre.transferTo(figlio, 300);

• abbiamo che:

this.withdraw(300); //this=padre

other.deposit(300); //other=figlio

Conversioni di tipo fra sottoclasse e superclasse

• Supponiamo ora che padre debba trasferire denaro ad un conto di tipo SavingsAccount:SavingsAccount cliente =

new SavingsAccount(0.5);

• Possiamo fare:padre.transferTo(cliente,200);

• L’assegnazione è corretta perché il metodo transferTo si aspetta di ricevere come parametro un riferimento a BA e invece riceve un riferimento a SA che è una sottoclasse: viene eseguita una conversione automatica.

Page 19: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

19

Conversioni di tipo fra sottoclasse e superclasse

• Il compilatore controlla solo che il riferimento di transferTo se non è di tipo BA sia di tipo classe derivata da BA.

• Avviene quindi la conversione:BankAccount other ←←←← cliente

• Ciò è analogo a quanto avviene quando si assegna ad una variabile reale un valore intero:

double a = 25;

• In realtà nei tipi base avviene una cosa diversa perchéil valore 25 (32 bit in complemento a 2) viene memorizzato in una sequenza di 64 bit con mantissa, esponente: è comunque lo stesso principio.

Conversioni di tipo fra sottoclasse e superclasse

• Il metodo transferTo invoca il metodo deposit:public void transferTo(BankAccount other,

double amount){

this.withdraw(amount);

other.deposit(amount);

}

• Ma quale deposit? • Il parametro other contiene un riferimento di tipo

SavingsAccount. Quindi sarà deposit di SavingsAccount: il metodo con cui si paga una tassa ad ogni versamento.

Polimorfismo

Polimorfismo

• Il termine polimorfismo deriva dal greco e significa “molte forme”.

• Nel trasferimento di denaro viene attivato:• il metodo deposit di BA, quando il parametro è

figlio• il metodo deposit di SA, quando il parametro è

cliente.

• La stessa operazione “versare denaro” viene eseguita in modi diversi che dipendono dal tipo dell’oggetto che viene effettivamente usato come parametro implicito.

Page 20: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

20

Polimorfismo

• Quando transferTo viene invocato, il riferimento passato a other “vede” un oggetto di tipo SA.

BA: other SA: cliente

Polimorfismo

• L’interprete Java sa che in other c’è un riferimento SA e quindi invoca deposit di SA.

• Il compilatore può solo verificare la possibilità che ciò possa avvenire.

• La scelta di quale sia effettivamente il riferimento viene fatta durante l’esecuzionedel programma, vale a dire, solo quando il metodo viene invocato.

Polimorfismo

• La scelta pertanto non è fatta in base al tipo del riferimento, other è definito di tipo BA, ma in base al tipo dell’oggetto che èrelamente memorizzato in other e che è di tipo SA.

• Il metodo ha lo stesso nome ma ha “forme diverse”.

• Il metodo deposit di SA sovrascrive il metodo deposit di BA.

Sovraccarico e polimorfismo

• Sovraccarico.

• Si parla di sovraccarico quando in una classe un metodo o un costruttore possiede parametri diversi; ad esempio:• in BankAccount abbiamo due costruttori, uno senza

parametro e uno con parametro

• il metodo println possiede parametri diversi a seconda del tipo base.

• È il compilatore che sceglie quale metodo invocare, prima che il programma venga eseguito.

• Si parla di selezione anticipata (early binding).

Page 21: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

21

Sovraccarico e polimorfismo

• Polimorfismo.

• Si parla di polimorfismo quando un metodo ha comportamenti diversi in relazione al tipo realmente memorizzato nel parametro implicito• utilizzo di deposit di BA oppure di SA

• È l’interprete JVM che decide durante l’esecuzione del programma quale metodo deve essere scelto.

• Si parla di selezione posticipata (late binding).

• Il compilatore controlla solo che il riferimento sia di tipo classe o sottoclasse.

Conversione inversa

Conversione inversa

• Si può fare la conversione inversa, vale a dire memorizzare un riferimento a superclasse in un riferimento a sottoclasse?

• È possibile fare una forzatura, cast, analogamente a quanto avviene per i tipi base.

• La conversione però ha senso solo se nel riferimento a superclasse è effettivamente memorizzato un riferimento a sottoclasse; in caso contrario si ha un errore.

Conversione inversa

• Esempio.SavingsAccount sA =

new SavingsAccount(2);

BankSAccount bA = sA;

SavingsAccount sA2 =

(SavingsAccount)bA; //cast

• Senza cast il compilatore segnala errore: tipi incompatibili.

• Se però bA (sul quale si fa il cast) non contiene un riferimento ad sA, durante l’esecuzione la JVM lancia l’eccezione ClassCastException.

Page 22: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

22

Conversione inversa

• Per essere sicuri che un riferimento contenga un riferimento valido per quell’oggetto, si può usare l’operatore instanceof.

• Sintassi.variabileoggetto instanceof Nomeclasse

• Esempio.if(bA instanceof SavingsAccount)

sA2 = (SavingsAccount)bA;

• L’operatore instanceof restituisce true, se la variabile è del tipo NomeClasse, false altrimenti.

TDA con numeri e oggetti

TDA con numeri e oggetti

• L’interfaccia Stack si riferisce ad elementi di tipo Object e così la sua realizzazione nella classe StackArray. Come primo esempio di Pila abbiamo visto una Pila di interi.

• È possibile “inserire” numeri interi in StackArray? Lo si può fare solo tramite le classi involucro: in tal modo si usa l’unica interfaccia Stack per rappresentare Pile di oggetti e di numeri, e si usano le sue realizzazioni con array e con lista concatenata.

TDA con numeri e oggetti

• Queste strutture generiche, definite tramite Object, sono molto comode perché possono contenere dati di tipo qualsiasi. Sono però scomode se si esegue l’estrazione dell’elemento o se si effettua una ricerca nella struttura. Infatti viene restituito un riferimento a Object, anche se il riferimento contenuto è quello si una sottoclasse.

• Pertanto è necessario effettuare un cast per ottenere un riferimento al tipo voluto.

• Se non è strettamente necessario, quando si devono usare TDA sui tipi base, conviene costruire la realizzazione specifica per il tipo base.

Page 23: Stampare una Pila - UniPDlaurap/didattica/Fondamenti-2-3/settimana8/... · Pila o Stack • Analogamente se vogliamo eseguire la ricerca di un elemento in una Pila: non ci sono assiomi

23

TDA con numeri e oggetti

Stack s = new StackArray();

Integer elem=5; //classe involucro

s.push(elem);

System.out.println("testa " + s.top());

Integer x = (Integer)(s.top()); //cast

int a = x;

System.out.println(a);

s.push(7); //direttamente

System.out.println("nuova testa "

+ s.top());

a = (Integer)(s.top());

System.out.println(a);