Ereditarietà Ereditarietà
C. Horstmann
C. Horstmann
Fondamenti di programmazione e Java 2
Fondamenti di programmazione e Java 2
3^ edizione Apogeo
3^ edizione Apogeo
trad. Nicola Fanizzi
trad. Nicola Fanizzi
corso di Programmazione, CdS: Informatica TPS
corso di Programmazione, CdS: Informatica TPS
Dip. di Informatica, Università degli studi di Bari
Dip. di Informatica, Università degli studi di Bari
2 2
Obiettivi Obiettivi
Conoscere il concetto di ereditarietà Conoscere il concetto di ereditarietà
Capire come ereditare e sovrascrivere metodi di Capire come ereditare e sovrascrivere metodi di superclassi
superclassi
Saper chiamare costruttori di superclassi Saper chiamare costruttori di superclassi
Conoscere il controllo d'accesso Conoscere il controllo d'accesso protected protected e e package
package
Capire la superclasse comune Capire la superclasse comune Object Object e e sovrascrivere i suoi metodi
sovrascrivere i suoi metodi toString toString e e equals equals
3 3
Introduzione all'Ereditarietà Introduzione all'Ereditarietà
Ereditarietà Ereditarietà : :
estendere le classi aggiungendo campi e metodi estendere le classi aggiungendo campi e metodi
Esempio: Esempio:
Conto Risparmio = Conto corrente con interessi Conto Risparmio = Conto corrente con interessi
class SavingsAccount extends BankAccount class SavingsAccount extends BankAccount { {
new methods new methods
new instance fields new instance fields }}
4 4
Introduzione all'Ereditarietà Introduzione all'Ereditarietà
SavingsAccount SavingsAccount eredita automaticamente eredita automaticamente tutti i metodi e campi d'istanza di
tutti i metodi e campi d'istanza di BankAccount BankAccount
Classe che viene estesa = Classe che viene estesa = superclasse superclasse ( ( BankAccount BankAccount ) )
Classe che estende = Classe che estende = sottoclasse sottoclasse ( ( SavingsAccount SavingsAccount ) )
SavingsAccount collegeFund = new SavingsAccount(10);
SavingsAccount collegeFund = new SavingsAccount(10);
// Savings account con interesse del 10%
// Savings account con interesse del 10%
collegeFund.deposit(500);
collegeFund.deposit(500);
// OK uso di un metodo BankAccount con oggetti SavingsAccount // OK uso di un metodo BankAccount con oggetti SavingsAccount
5 5
Introduzione all'Ereditarietà Introduzione all'Ereditarietà
Estendere una classe ≠ implementare un'interfaccia: Estendere una classe ≠ implementare un'interfaccia:
la sottoclasse eredita la sottoclasse eredita
sia sia il comportamento il comportamento sia sia lo stato lo stato
Un vantaggio dell'ereditarietà è il riuso di codice Un vantaggio dell'ereditarietà è il riuso di codice
6 6
Diagramma di Ereditarietà Diagramma di Ereditarietà
Ogni classe estende Ogni classe estende
direttamente o indirettamente direttamente o indirettamente
la classe
la classe Object Object
Figure 1:
An Inheritance Diagram
7 7
Introduzione all'Ereditarietà Introduzione all'Ereditarietà
Nella sottoclasse, si specificano i campi e i metodi Nella sottoclasse, si specificano i campi e i metodi aggiunti e quelli modificati o sovrascritti
aggiunti e quelli modificati o sovrascritti
public class SavingsAccount extends BankAccount public class SavingsAccount extends BankAccount { {
public SavingsAccount(double rate) public SavingsAccount(double rate) {
{
interestRate = rate;
interestRate = rate;
} }
public void addInterest() public void addInterest() {
{
double interest = getBalance() * interestRate / 100;
double interest = getBalance() * interestRate / 100;
deposit(interest);
deposit(interest);
} }
private double interestRate;
private double interestRate;
} }
8 8
Introduzione all'Ereditarietà Introduzione all'Ereditarietà
Incapsulamento Incapsulamento : : addInterest addInterest chiama chiama getBalance
getBalance piuttosto che aggiornare il campo piuttosto che aggiornare il campo balance
balance della superclasse (campo privato) della superclasse (campo privato)
Notare che Notare che addInterest addInterest chiama chiama getBalance
getBalance senza specificare un parametro senza specificare un parametro
implicito (chiamate applicate allo stesso oggetto)
implicito (chiamate applicate allo stesso oggetto)
9 9
Struttura di un Oggetto Struttura di un Oggetto
di una Sottoclasse di una Sottoclasse
L'oggetto L'oggetto SavingsAccount SavingsAccount eredita il campo eredita il campo balance
balance da da BankAccount BankAccount , e guadagna un , e guadagna un campo addizionale:
campo addizionale: interestRate interestRate : :
Figure 2:
Layout of a Subclass Object
10 10
Sintassi 13.1: Ereditarietà Sintassi 13.1: Ereditarietà
class
class SubclassNameSubclassName extendsextends SuperclassNameSuperclassName {{
methods methods
instance fields instance fields }}
Esempio: Esempio:
public class SavingsAccount extends BankAccount public class SavingsAccount extends BankAccount { {
public SavingsAccount(double rate) public SavingsAccount(double rate) { {
interestRate = rate; interestRate = rate;
} }
public void addInterest() public void addInterest() { {
double interest = getBalance() * interestRate / 100; double interest = getBalance() * interestRate / 100;
deposit(interest); deposit(interest);
} }
private double interestRate; private double interestRate;
11 11
Sintassi 13.1: Ereditarietà Sintassi 13.1: Ereditarietà
Scopo Scopo : :
definire una nuova classe che eredita da una classe definire una nuova classe che eredita da una classe
esistente e esistente e
definire i metodi e i campi da aggiungere alla nuova definire i metodi e i campi da aggiungere alla nuova
classe
classe
12 12
Gerarchie d'Ereditarietà Gerarchie d'Ereditarietà
Insiemi di classi possono costituire complesse Insiemi di classi possono costituire complesse gerarchie di ereditarietà
gerarchie di ereditarietà
Esempio Esempio : :
13 13
Esempio di Gerarchia di Esempio di Gerarchia di Ereditarietà: la Gerarchia
Ereditarietà: la Gerarchia Swing Swing
Figure 4:
A Part of the Hierarchy of Swing User
Interface Components
14 14
Esempio di Gerarchia di Esempio di Gerarchia di Ereditarietà: la Gerarchia
Ereditarietà: la Gerarchia Swing Swing
La superclasse La superclasse JComponent JComponent ha ha i metodi i metodi getWidth
getWidth , , getHeight getHeight
La classe La classe AbstractButton AbstractButton ha i metodi per ha i metodi per settare/leggere testo e icona del bottone
settare/leggere testo e icona del bottone
15 15
Una Gerarchia più Semplice:
Una Gerarchia più Semplice:
la Gerarchia dei Conti Correnti la Gerarchia dei Conti Correnti
Si consideri una banca che offra ai suoi clienti i Si consideri una banca che offra ai suoi clienti i seguenti tipi di conto:
seguenti tipi di conto:
Conto Assegni ( Conto Assegni ( checkingAccount checkingAccount ): ):
nessun interesse; nessun interesse;
limitato numero di operazioni gratuite al mese, limitato numero di operazioni gratuite al mese,
operazioni supplementari dietro pagamento di un piccola operazioni supplementari dietro pagamento di un piccola commissione
commissione
Conto Risparmio (savingsAccount Conto Risparmio ( savingsAccount ): ):
Acquista interessi calcolati su base mensile Acquista interessi calcolati su base mensile
16 16
Una Gerarchia più Semplice:
Una Gerarchia più Semplice:
la Gerarchia dei Conti Correnti la Gerarchia dei Conti Correnti
Figure 5:
Gerarchia Gerarchia
d'ereditarietà
d'ereditarietà
17 17
Una Gerarchia più Semplice:
Una Gerarchia più Semplice:
la Gerarchia dei Conti Correnti la Gerarchia dei Conti Correnti
Tutti i conti supportano il metodo Tutti i conti supportano il metodo getBalance getBalance
Tutti i conti supportano i metodi Tutti i conti supportano i metodi deposit deposit e e withdraw
withdraw ma le implementazioni differiscono ma le implementazioni differiscono
Il conto assegni necessita di un metodo deductFees Il conto assegni necessita di un metodo deductFees ; ;
Il conto risparmio necessita di un metodo Il conto risparmio necessita di un metodo addInterest
addInterest
18 18
Ereditare Metodi Ereditare Metodi
1) 1) Sovrascrivere ( Sovrascrivere ( override override ) un metodo: ) un metodo:
Fornire una diversa implementazione di un metodo Fornire una diversa implementazione di un metodo esistente nella superclasse
esistente nella superclasse
Esso deve avere la stessa firma ( Esso deve avere la stessa firma ( signature signature ): ):
stesso
stesso numero di parametri e numero di parametri e stesso stesso tipo tipo
Se si applica il metodo ad un oggetto della sottoclasse Se si applica il metodo ad un oggetto della sottoclasse verrà eseguito il metodo sovrascritto (
verrà eseguito il metodo sovrascritto ( overriding overriding ) )
2) 2) Ereditare un metodo: Ereditare un metodo:
Non si fornisce una nuova implementazione di un metodo Non si fornisce una nuova implementazione di un metodo esistente nella superclasse
esistente nella superclasse
Il metodo della superclasse può ancora essere applicato Il metodo della superclasse può ancora essere applicato all'oggetto della sottoclasse
all'oggetto della sottoclasse
19 19
Ereditare Metodi Ereditare Metodi
3) 3) Aggiungere un metodo: Aggiungere un metodo:
Fornire un nuovo metodo che non esiste nella Fornire un nuovo metodo che non esiste nella superclasse
superclasse
Il nuovo metodo può essere applicato Il nuovo metodo può essere applicato solo solo ad oggetti ad oggetti della sottoclasse
della sottoclasse
20 20
Ereditare Campi d'Istanza Ereditare Campi d'Istanza
Non Non si possono sovrascrivere i campi si possono sovrascrivere i campi
Ereditare un campo: Ereditare un campo:
tutti i campi della superclasse sono automaticamente tutti i campi della superclasse sono automaticamente
ereditati ereditati
Aggiungere un campo: Aggiungere un campo:
fornire un nuovo campo che non esiste nella fornire un nuovo campo che non esiste nella
superclasse
superclasse
21 21
Ereditare Campi d'Istanza Ereditare Campi d'Istanza
Che succede se si definisce un Che succede se si definisce un nuovo nuovo campo con campo con lo lo stesso stesso nome d'un campo della superclasse? nome d'un campo della superclasse?
Ogni oggetto avrebbe due campi d'istanza con lo stesso Ogni oggetto avrebbe due campi d'istanza con lo stesso nome nome
I campi potrebbero avere diversi valori I campi potrebbero avere diversi valori
Lecito ma largamente indesiderabile Lecito ma largamente indesiderabile
22 22
Implementare la Classe Implementare la Classe
CheckingAccount CheckingAccount
Sovrascrive Sovrascrive deposit deposit e e withdraw withdraw per poter per poter incrementare il contatore del numero di operazioni incrementare il contatore del numero di operazioni ( ( transazioni transazioni ) effettuate: ) effettuate:
public class CheckingAccount extends BankAccount public class CheckingAccount extends BankAccount { {
public void deposit(double amount) {. . .}
public void deposit(double amount) {. . .}
public void withdraw(double amount) {. . .}
public void withdraw(double amount) {. . .}
public void deductFees() {. . .}
public void deductFees() {. . .} // nuovo metodo // nuovo metodo private int transactionCount;
private int transactionCount; // nuovo campo// nuovo campo } }
23 23
Implementare la Classe Implementare la Classe
CheckingAccount CheckingAccount
Ogni oggetto Ogni oggetto CheckingAccount CheckingAccount ha due campi d'istanza:
ha due campi d'istanza:
balance balance
ereditato da BankAccount ereditato da BankAccount
transactionCount transactionCount
nuovo per CheckingAccount nuovo per CheckingAccount
24 24
Implementare la Classe Implementare la Classe
CheckingAccount CheckingAccount
Si possono applicare quattro metodi agli oggetti della Si possono applicare quattro metodi agli oggetti della classe
classe CheckingAccount CheckingAccount : :
getBalance() getBalance()
Ereditato da BankAccount Ereditato da BankAccount
deposit(double amount) deposit(double amount)
Sovrascrive il metodo di BankAccount Sovrascrive il metodo di BankAccount
withdraw(double amount) withdraw(double amount)
Sovrascrive il metodo di BankAccount Sovrascrive il metodo di BankAccount
deductFees() deductFees()
Nuovo per CheckingAccount Nuovo per CheckingAccount
25 25
I Campi Ereditati Sono Privati I Campi Ereditati Sono Privati
Si consideri il metodo Si consideri il metodo deposit deposit delle classe delle classe CheckingAccount
CheckingAccount
Non si può semplicemente Non si può semplicemente aggiungere
aggiungere amount amount a a balance balance
balance balance è campo un è campo un privato privato della superclasse della superclasse
public void deposit(double amount) public void deposit(double amount) { {
transactionCount++;
transactionCount++;
// aggiunge amount a balance // aggiunge amount a balance . . .
. . . }}
26 26
I Campi Ereditati Sono Privati I Campi Ereditati Sono Privati
Una sottoclasse Una sottoclasse non non ha accesso ai campi privati ha accesso ai campi privati della sua superclasse
della sua superclasse
La sottoclasse La sottoclasse deve deve usar l'interfaccia pubblica usar l'interfaccia pubblica
27 27
Invocare un Metodo Invocare un Metodo
della Superclasse della Superclasse
Non si può semplicemente chiamare Non si può semplicemente chiamare deposit(amount)
deposit(amount) nel metodo
nel metodo deposit deposit di di CheckingAccount CheckingAccount
Sarebbe lo stesso di: Sarebbe lo stesso di:
this.deposit(amount) this.deposit(amount)
Chiamerebbe lo stesso metodo (ricorsione infinita) Chiamerebbe lo stesso metodo (ricorsione infinita)
Invece, si invoca il metodo della superclasse: Invece, si invoca il metodo della superclasse:
super.deposit(amount)
super.deposit(amount)
28 28
Invocare un Metodo Invocare un Metodo
della Superclasse della Superclasse
Adesso si chiama il metodo Adesso si chiama il metodo deposit deposit della classe
della classe BankAccount BankAccount
Metodo completo: Metodo completo:
public void deposit(double amount) public void deposit(double amount) { {
transactionCount++;
transactionCount++;
// sommare amount a balance: super.deposit(amount); // sommare amount a balance: super.deposit(amount);
} }
29 29
Sintassi 13.2: Chiamare un Sintassi 13.2: Chiamare un
Metodo di Superclasse Metodo di Superclasse
super.
super.methodNamemethodName((parametersparameters))
Esempio: Esempio:
public void deposit(double amount) public void deposit(double amount) {{
transactionCount++;
transactionCount++;
super.deposit(amount);
super.deposit(amount);
}}
Scopo Scopo : chiamare un metodo della superclasse : chiamare un metodo della superclasse invece di quello della classe corrente
invece di quello della classe corrente
30 30
Implementare i Restanti Metodi Implementare i Restanti Metodi
public class CheckingAccount extends BankAccount public class CheckingAccount extends BankAccount { {
. . . . . .
public void withdraw(double amount) public void withdraw(double amount) {
{
transactionCount++;
transactionCount++;
// sottrae amount da balance // sottrae amount da balance super.withdraw(amount);
super.withdraw(amount);
} }
31 31
Implementare i Restanti Metodi Implementare i Restanti Metodi
public void deductFees() public void deductFees() {
{
if (transactionCount > FREE_TRANSACTIONS) if (transactionCount > FREE_TRANSACTIONS) {
{
double fees = TRANSACTION_FEE double fees = TRANSACTION_FEE
* (transactionCount - FREE_TRANSACTIONS);
* (transactionCount - FREE_TRANSACTIONS);
super.withdraw(fees);
super.withdraw(fees);
} }
transactionCount = 0;
transactionCount = 0;
} }
. . . . . .
private static final int FREE_TRANSACTIONS = 3;
private static final int FREE_TRANSACTIONS = 3;
private static final double TRANSACTION_FEE = 2.0;
private static final double TRANSACTION_FEE = 2.0;
}}
32 32
Errore Comune:
Errore Comune:
Oscurare Campi d'Istanza Oscurare Campi d'Istanza
Una sottoclasse non ha accesso ai campi privati Una sottoclasse non ha accesso ai campi privati della superclasse
della superclasse
Errore da principianti: "risolvere" il problema Errore da principianti: "risolvere" il problema
aggiungendo un altro campo con lo stesso nome:
aggiungendo un altro campo con lo stesso nome:
public class CheckingAccount extends BankAccount public class CheckingAccount extends BankAccount { {
public void deposit(double amount) public void deposit(double amount)
{ {
transactionCount++;
transactionCount++;
balance = balance + amount;
balance = balance + amount;
} }
. . . . . .
private double balance; private double balance; // da NON fare// da NON fare } }
33 33
Errore Comune:
Errore Comune:
Oscurare Campi d'Istanza Oscurare Campi d'Istanza
Adesso il metodo Adesso il metodo deposit deposit viene compilato senza viene compilato senza errori, ma aggiorna il campo
errori, ma aggiorna il campo balance balance sbagliato ! sbagliato !
Figure 6:
Shadowing Instance Fields
34 34
Costruzione di Sottoclassi Costruzione di Sottoclassi
super super seguito dalle parentesi seguito dalle parentesi
indica una chiamata al costruttore della superclasse indica una chiamata al costruttore della superclasse
public class CheckingAccount extends BankAccount public class CheckingAccount extends BankAccount { {
public CheckingAccount(double initialBalance) public CheckingAccount(double initialBalance) {
{
// Costruisce la superclasse // Costruisce la superclasse super(initialBalance);
super(initialBalance);
// Inizializza il contatore // Inizializza il contatore transactionCount = 0;
transactionCount = 0;
} }
. . . . . . } }
35 35
Costruzione di Sottoclassi Costruzione di Sottoclassi
Deve Deve essere essere la prima la prima istruzione nel costruttore istruzione nel costruttore della sottoclasse
della sottoclasse
Se il costruttore della sottoclasse non chiama quello Se il costruttore della sottoclasse non chiama quello della superclasse, si usa il costruttore di default
della superclasse, si usa il costruttore di default della superclasse
della superclasse
Costruttore di Default: costruttore senza parametri Costruttore di Default: costruttore senza parametri
Se tutti i costruttori della superclasse richiedono Se tutti i costruttori della superclasse richiedono
parametri, allora il compilatore registra un errore
parametri, allora il compilatore registra un errore
36 36
Sintassi 13.1: Chiamare il Sintassi 13.1: Chiamare il Costruttore della Superclasse Costruttore della Superclasse
className
className((parameters)parameters) {{
super(
super(parameters);parameters);
. . . . . . }}
Esempio Esempio : :
public CheckingAccount(double initialBalance) public CheckingAccount(double initialBalance) { {
super(initialBalance);
super(initialBalance);
transactionCount = 0;
transactionCount = 0;
}}
Scopo Scopo : Invocare un costruttore della superclasse : Invocare un costruttore della superclasse Si noti che questa istruzione deve essere la prima Si noti che questa istruzione deve essere la prima
nel costruttore della sottoclasse.
nel costruttore della sottoclasse.
37 37
Conversioni tra Tipi Conversioni tra Tipi Sottoclasse e Superclasse Sottoclasse e Superclasse
È lecito convertire È lecito convertire
i riferimenti a sottoclassi i riferimenti a sottoclassi
in riferimenti a superclassi in riferimenti a superclassi
SavingsAccount collegeFund = new SavingsAccount(10);
SavingsAccount collegeFund = new SavingsAccount(10);
BankAccount anAccount = collegeFund;
BankAccount anAccount = collegeFund;
Object anObject = collegeFund;
Object anObject = collegeFund;
38 38
Conversioni tra Tipi Conversioni tra Tipi Sottoclasse e Superclasse Sottoclasse e Superclasse
I tre riferimenti ad oggetti in I tre riferimenti ad oggetti in collegeFund collegeFund , , anAccount
anAccount , e , e anObject anObject si riferiscono tutti allo si riferiscono tutti allo stesso oggetto di tipo
stesso oggetto di tipo SavingsAccount SavingsAccount
Figure 7:
Variables of Different Types
39 39
Conversioni tra Tipi Conversioni tra Tipi Sottoclasse e Superclasse Sottoclasse e Superclasse
I riferimenti a superclasse non sanno tutta la storia I riferimenti a superclasse non sanno tutta la storia dell'oggetto:
dell'oggetto:
Quando si converte un oggetto d'una sottoclasse in Quando si converte un oggetto d'una sottoclasse in uno del tipo della superclasse:
uno del tipo della superclasse:
Il valore del riferimento rimane lo stesso–è la locazione di Il valore del riferimento rimane lo stesso–è la locazione di memoria dell'oggetto
memoria dell'oggetto
Tuttavia, si dispone di minore informazione circa l'oggetto Tuttavia, si dispone di minore informazione circa l'oggetto
anAccount.deposit(1000);
anAccount.deposit(1000); // OK // OK anAccount.addInterest();
anAccount.addInterest();
// No—non è un metodo della classe cui appartiene anAccount // No—non è un metodo della classe cui appartiene anAccount
40 40
Conversioni tra Tipi Conversioni tra Tipi Sottoclasse e Superclasse Sottoclasse e Superclasse
Perché si dovrebbe essere disposti a conoscere Perché si dovrebbe essere disposti a conoscere meno circa un oggetto ?
meno circa un oggetto ?
Riusare codice che sa della superclasse ma non della Riusare codice che sa della superclasse ma non della sottoclasse:
sottoclasse:
Può essere usato per trasferire denaro da ogni tipo Può essere usato per trasferire denaro da ogni tipo di di BankAccount BankAccount
public void transfer(double amount, BankAccount other) public void transfer(double amount, BankAccount other) { {
withdraw(amount);
withdraw(amount);
other.deposit(amount);
other.deposit(amount);
}}
41 41
Conversioni tra Tipi Conversioni tra Tipi Sottoclasse e Superclasse Sottoclasse e Superclasse
Occasionalmente si necessita di convertire Occasionalmente si necessita di convertire un riferimento a superclasse
un riferimento a superclasse in un riferimento a sottoclasse in un riferimento a sottoclasse
Questo Questo cast cast è è pericoloso pericoloso : :
se ci si sbaglia viene lanciata un eccezione se ci si sbaglia viene lanciata un eccezione
BankAccount anAccount = (BankAccount) anObject;
BankAccount anAccount = (BankAccount) anObject;
42 42
Conversioni tra Tipi Conversioni tra Tipi Sottoclasse e Superclasse Sottoclasse e Superclasse
Soluzione: usare l'operatore Soluzione: usare l'operatore instanceof instanceof
instanceof instanceof : :
controlla se un oggetto appartenga o meno controlla se un oggetto appartenga o meno
ad un particolare tipo ad un particolare tipo
if (anObject instanceof BankAccount) if (anObject instanceof BankAccount) { {
BankAccount anAccount = (BankAccount) anObject;
BankAccount anAccount = (BankAccount) anObject;
. . . . . . } }
43 43
Sintassi 13.4:
Sintassi 13.4:
L'Operatore
L'Operatore Instanceof Instanceof
object
object instanceofinstanceof TypeNameTypeName
Esempio Esempio : :
if (anObject instanceof BankAccount) if (anObject instanceof BankAccount) { {
BankAccount anAccount = (BankAccount) anObject;
BankAccount anAccount = (BankAccount) anObject;
. . . . . . }}
Scopo Scopo : : (operatore booleano) (operatore booleano) restituisce
restituisce true true se l'oggetto è un'istanza di se l'oggetto è un'istanza di TypeName
TypeName (o uno di suoi sottotipi), (o uno di suoi sottotipi),
e e false false altrimenti altrimenti
44 44
Polimorfismo Polimorfismo
In Java, il tipo di una variabile non determina In Java, il tipo di una variabile non determina completamente il tipo d'oggetto al quale essa si completamente il tipo d'oggetto al quale essa si
riferisce riferisce
Le chiamate dei metodi sono determinate dal tipo Le chiamate dei metodi sono determinate dal tipo effettivo dell'oggetto e non dal tipo di riferimento effettivo dell'oggetto e non dal tipo di riferimento
BankAccount aBankAccount = new SavingsAccount(1000);
BankAccount aBankAccount = new SavingsAccount(1000);
// aBankAccount mantiene un riferimento a un SavingsAccount // aBankAccount mantiene un riferimento a un SavingsAccount
BankAccount anAccount = new CheckingAccount();
BankAccount anAccount = new CheckingAccount();
anAccount.deposit(1000);
anAccount.deposit(1000);
// chiama "deposit" di CheckingAccount // chiama "deposit" di CheckingAccount
45 45
Polimorfismo Polimorfismo
Il compilatore necessita di controllare che si Il compilatore necessita di controllare che si invochino solo metodi leciti
invochino solo metodi leciti
Object anObject = new BankAccount();
Object anObject = new BankAccount();
anObject.deposit(1000);
anObject.deposit(1000); // sbagliato ! // sbagliato !
46 46
Polimorfismo Polimorfismo
Polimorfismo Polimorfismo : abilità di riferirsi ad oggetti di tipi : abilità di riferirsi ad oggetti di tipi differenti dal comportamento variabile
differenti dal comportamento variabile
Polimorfismo all'opera: Polimorfismo all'opera:
A seconda dei tipi di amount ed altro, A seconda dei tipi di amount ed altro, saranno chiamate diverse versioni di
saranno chiamate diverse versioni di withdraw withdraw e e deposit
deposit
public void transfer(double amount, BankAccount other) public void transfer(double amount, BankAccount other) { {
withdraw(amount);
withdraw(amount); // abbreviazione di this.withdraw(amount)// abbreviazione di this.withdraw(amount) other.deposit(amount);
other.deposit(amount);
}}
47 47
AccountTester.java AccountTester.java
01: /**
01: /**
02: Programma per testare la classe BankAccount 02: Programma per testare la classe BankAccount 03: e le sue sottoclassi.
03: e le sue sottoclassi.
04: */
04: */
05: public class AccountTester 05: public class AccountTester 06: {
06: {
07: public static void main(String[] args) 07: public static void main(String[] args) 08: {
08: {
09: SavingsAccount momsSavings 09: SavingsAccount momsSavings
10: = new SavingsAccount(0.5);
10: = new SavingsAccount(0.5);
11:
11:
12: CheckingAccount harrysChecking 12: CheckingAccount harrysChecking 13: = new CheckingAccount(100);
13: = new CheckingAccount(100);
14:
14:
15: momsSavings.deposit(10000);
15: momsSavings.deposit(10000);
16: 16:
48 48
AccountTester.java AccountTester.java
17: momsSavings.transfer(2000, harrysChecking);
17: momsSavings.transfer(2000, harrysChecking);
18: harrysChecking.withdraw(1500);
18: harrysChecking.withdraw(1500);
19: harrysChecking.withdraw(80);
19: harrysChecking.withdraw(80);
20: 20:
21: momsSavings.transfer(1000, harrysChecking);
21: momsSavings.transfer(1000, harrysChecking);
22: harrysChecking.withdraw(400);
22: harrysChecking.withdraw(400);
23: 23:
24: // Simulate end of month 24: // Simulate end of month 25: momsSavings.addInterest();
25: momsSavings.addInterest();
26: harrysChecking.deductFees();
26: harrysChecking.deductFees();
27:
27:
28: System.out.println("Mom's savings balance = $“
28: System.out.println("Mom's savings balance = $“
29: + momsSavings.getBalance());
29: + momsSavings.getBalance());
30: 30:
31: System.out.println("Harry's checking balance = $“
31: System.out.println("Harry's checking balance = $“
32: + harrysChecking.getBalance());
32: + harrysChecking.getBalance());
33: } 33: } 34: } 34: }
49 49
BankAccount.java BankAccount.java
01: /**
01: /**
02: Un conto ha un balance modificabile con 02: Un conto ha un balance modificabile con 03: depositi e prelievi.
03: depositi e prelievi.
04: */
04: */
05: public class BankAccount 05: public class BankAccount 06: {
06: { 07: /**
07: /**
08: Costruisce un conto con saldo zero.
08: Costruisce un conto con saldo zero.
09: */
09: */
10: public BankAccount() 10: public BankAccount() 11: {
11: {
12: balance = 0;
12: balance = 0;
13: } 13: } 14: 14:
15: /**
15: /**
16: Costruisce un conto con un dato saldo.
16: Costruisce un conto con un dato saldo.
17: @param initialBalance saldo iniziale 17: @param initialBalance saldo iniziale 18: */
18: */
50 50
BankAccount.java BankAccount.java
19: public BankAccount(double initialBalance) 19: public BankAccount(double initialBalance) 20: {
20: {
21: balance = initialBalance;
21: balance = initialBalance;
22: } 22: } 23:
23:
24: /**
24: /**
25: Deposita denaro sul conto.
25: Deposita denaro sul conto.
26: @param amount l'ammontare da depositare 26: @param amount l'ammontare da depositare 27: */
27: */
28: public void deposit(double amount) 28: public void deposit(double amount) 29: {
29: {
30: balance = balance + amount;
30: balance = balance + amount;
31: } 31: } 32: 32:
33: /**
33: /**
34: ritira denaro dal conto.
34: ritira denaro dal conto.
35: @param amount l'ammontare da ritirare 35: @param amount l'ammontare da ritirare 36: */
36: */
51 51
BankAccount.java BankAccount.java
37: public void withdraw(double amount) 37: public void withdraw(double amount) 38: {
38: {
39: balance = balance - amount;
39: balance = balance - amount;
40: } 40: } 41: 41:
42: /**
42: /**
43: Ottiene il saldo corrente dal conto.
43: Ottiene il saldo corrente dal conto.
44: @return il saldo corrente 44: @return il saldo corrente 45: */
45: */
46: public double getBalance() 46: public double getBalance() 47: {
47: {
48: return balance;
48: return balance;
49: } 49: } 50:
50:
51: /**
51: /**
52: Trasferisce denaro dal conto ad altro conto 52: Trasferisce denaro dal conto ad altro conto 53: @param amount l'ammondtare del trasferimento 53: @param amount l'ammondtare del trasferimento 54: @param other l'altro conto
54: @param other l'altro conto 55: */
55: */
52 52
BankAccount.java BankAccount.java
56: public void transfer(double amount, BankAccount other) 56: public void transfer(double amount, BankAccount other) 57: {
57: {
58: withdraw(amount);
58: withdraw(amount);
59: other.deposit(amount);
59: other.deposit(amount);
60: } 60: } 61: 61:
62: private double balance;
62: private double balance;
63: } 63: }
53 53
CheckingAccount.java CheckingAccount.java
01: /**
01: /**
02: Un conto assegni che carica commissioni su operazioni.
02: Un conto assegni che carica commissioni su operazioni.
03: */
03: */
04: public class CheckingAccount extends BankAccount 04: public class CheckingAccount extends BankAccount 05: {
05: {
06: /**
06: /**
07: Costruisce un conto assegni con il dato saldo.
07: Costruisce un conto assegni con il dato saldo.
08: @param initialBalance saldo iniziale 08: @param initialBalance saldo iniziale 09: */
09: */
10: public CheckingAccount(double initialBalance) 10: public CheckingAccount(double initialBalance) 11: {
11: {
12: // Costruisce la superclasse 12: // Costruisce la superclasse 13: super(initialBalance);
13: super(initialBalance);
14:
14:
15: // Inizializza il contatore operazioni 15: // Inizializza il contatore operazioni 16: transactionCount = 0;
16: transactionCount = 0;
17: } 17: } 18: 18:
54 54
CheckingAccount.java CheckingAccount.java
19: public void deposit(double amount) 19: public void deposit(double amount) 20: {
20: {
21: transactionCount++;
21: transactionCount++;
22: // aggiunge amount a balance 22: // aggiunge amount a balance 23: super.deposit(amount);
23: super.deposit(amount);
24: } 24: } 25:
25:
26: public void withdraw(double amount) 26: public void withdraw(double amount) 27: {
27: {
28: transactionCount++;
28: transactionCount++;
29: // sottrae amount da balance 29: // sottrae amount da balance 30: super.withdraw(amount);
30: super.withdraw(amount);
31: } 31: } 32: 32:
33: /**
33: /**
34: deduce le commissioni accumulate e ripristina il 34: deduce le commissioni accumulate e ripristina il 35: contatore delle operazioni.
35: contatore delle operazioni.
36: */
36: */
55 55
CheckingAccount.java CheckingAccount.java
37: public void deductFees() 37: public void deductFees() 38: {
38: {
39: if (transactionCount > FREE_TRANSACTIONS) 39: if (transactionCount > FREE_TRANSACTIONS) 40: {
40: {
41: double fees = TRANSACTION_FEE * 41: double fees = TRANSACTION_FEE *
42: (transactionCount - FREE_TRANSACTIONS);
42: (transactionCount - FREE_TRANSACTIONS);
43: super.withdraw(fees);
43: super.withdraw(fees);
44: } 44: }
45: transactionCount = 0;
45: transactionCount = 0;
46: } 46: } 47: 47:
48: private int transactionCount;
48: private int transactionCount;
49: 49:
50: private static final int FREE_TRANSACTIONS = 3;
50: private static final int FREE_TRANSACTIONS = 3;
51: private static final double TRANSACTION_FEE = 2.0;
51: private static final double TRANSACTION_FEE = 2.0;
52: } 52: }
56 56
SavingsAccount.java SavingsAccount.java
01: /**
01: /**
02: Un conto che guadagna interessi ad un tasso fissato.
02: Un conto che guadagna interessi ad un tasso fissato.
03: */
03: */
04: public class SavingsAccount extends BankAccount 04: public class SavingsAccount extends BankAccount 05: {
05: { 06: /**
06: /**
07: Costruisce un conto con un dato tasso d'interesse.
07: Costruisce un conto con un dato tasso d'interesse.
08: @param rate il tasso d'interesse 08: @param rate il tasso d'interesse 09: */
09: */
10: public SavingsAccount(double rate) 10: public SavingsAccount(double rate) 11: {
11: {
12: interestRate = rate;
12: interestRate = rate;
13: } 13: } 14:14:
57 57
SavingsAccount.java SavingsAccount.java
15: /**
15: /**
16: Aggiunge gli interessi maturati al saldo del conto.
16: Aggiunge gli interessi maturati al saldo del conto.
17: */
17: */
18: public void addInterest() 18: public void addInterest() 19: {
19: {
20: double interest = getBalance() * interestRate / 100;
20: double interest = getBalance() * interestRate / 100;
21: deposit(interest);
21: deposit(interest);
22: } 22: } 23: 23:
24: private double interestRate;
24: private double interestRate;
25: } 25: }
58 58
Output Output
SavingsAccount.java SavingsAccount.java
Mom's savings balance = $7035.0 Mom's savings balance = $7035.0 Harry's checking balance = $1116.0 Harry's checking balance = $1116.0
59 59
Controllo d'Accesso Controllo d'Accesso
Java ha quattro livelli di controllo d'accesso ai campi, Java ha quattro livelli di controllo d'accesso ai campi, metodi e classe:
metodi e classe:
Accesso Pubblico ( Accesso Pubblico ( public public ) )
Si può accedere da metodi di tutte le classi Si può accedere da metodi di tutte le classi
Accesso Privato ( Accesso Privato ( private private ) )
Si può accedere da metodi della loro prorpa classe Si può accedere da metodi della loro prorpa classe
Accesso Protetto ( Accesso Protetto ( protected protected ) )
Cfr. Argomenti avanzati 12.3 Cfr. Argomenti avanzati 12.3
Accesso di Pacchetto (package Accesso di Pacchetto ( package ) )
Default, quando non si specifica un altro accesso Default, quando non si specifica un altro accesso
Si può accedere da tutte le classi nello stesso package Si può accedere da tutte le classi nello stesso package
Va bene per classi default, non altrettanto per i campi d'istanza Va bene per classi default, non altrettanto per i campi d'istanza
60 60
Livelli d'Accesso Raccomandati Livelli d'Accesso Raccomandati
Campi d'istanza e statici: sempre Campi d'istanza e statici: sempre private private . . Tranne:
Tranne:
Le costanti Le costanti public static final public static final sono utili e sono utili e sicure
sicure
Alcuni oggetti, come System.out Alcuni oggetti, come System.out , hanno bisogno di , hanno bisogno di essere accessibili a tutti i programmi (
essere accessibili a tutti i programmi ( public public ) )
A volte, le classi di un pacchetto devono collaborare molto A volte, le classi di un pacchetto devono collaborare molto strettamente (si dà ad alcuni campi l'accesso di
strettamente (si dà ad alcuni campi l'accesso di pacchetto); meglio le classi interne
pacchetto); meglio le classi interne
61 61
Livelli d'Accesso Raccomandati Livelli d'Accesso Raccomandati
Metodi: Metodi: public public o o private private
Classi ed Interfacce: Classi ed Interfacce: public public o pacchetto o pacchetto
Alternativa migliore all'accesso di pacchetto: classi interne Alternativa migliore all'accesso di pacchetto: classi interne
In generale, le classi interne non dovrebbero essere pubbliche In generale, le classi interne non dovrebbero essere pubbliche (ci sono alcune eccezioni, es.,
(ci sono alcune eccezioni, es., Ellipse2D.Double Ellipse2D.Double ) )
Attenzione all'accesso di pacchetto involontario Attenzione all'accesso di pacchetto involontario (dimenticando di specificare
(dimenticando di specificare public
public o o private private ) )
62 62
Object Object : : la Superclasse Universale la Superclasse Universale
Ogni classe definita senza una clausola Ogni classe definita senza una clausola extends extends esplicita estende automaticamente
esplicita estende automaticamente Object Object
Figure 8:
63 63
Object Object : : la Superclasse Universale la Superclasse Universale
Metodi più utili: Metodi più utili:
String toString() String toString()
boolean equals(Object otherObject) boolean equals(Object otherObject)
Object clone() Object clone()
È una buona idea quella di sovrascrivere questi È una buona idea quella di sovrascrivere questi metodi nelle proprie classi
metodi nelle proprie classi
64 64
Sovrascrivere il Metodo Sovrascrivere il Metodo
tostring() tostring()
Restituisce una rappresentazione in forma di stringa Restituisce una rappresentazione in forma di stringa dell'oggetto
dell'oggetto
Utile per il debugging: Utile per il debugging:
Rectangle box = new Rectangle(5, 10, 20, 30);
Rectangle box = new Rectangle(5, 10, 20, 30);
String s = box.toString();
String s = box.toString();
// setta s a "java.awt.Rectangle[x=5,y=10,width=20,height=30]"
// setta s a "java.awt.Rectangle[x=5,y=10,width=20,height=30]"
65 65
Sovrascrivere il Metodo Sovrascrivere il Metodo
toString toString
toString toString viene chiamato ogni qual volta si viene chiamato ogni qual volta si concatena una stringa con un oggetto:
concatena una stringa con un oggetto:
Object.toString Object.toString stampa il nome della classe stampa il nome della classe e l'hash-code dell'oggetto:
e l'hash-code dell'oggetto:
"box=" + box;
"box=" + box;
// cioè "box=java.awt.Rectangle[x=5,y=10,width=20,height=30]"
// cioè "box=java.awt.Rectangle[x=5,y=10,width=20,height=30]"
BankAccount momsSavings = new BankAccount(5000);
BankAccount momsSavings = new BankAccount(5000);
String s = momsSavings.toString();
String s = momsSavings.toString();
// setta s a qualcosa come "BankAccount@d24606bf"
// setta s a qualcosa come "BankAccount@d24606bf"
66 66
Sovrascrivere il Metodo Sovrascrivere il Metodo
tostring() tostring()
Per una rappresentazione più carina di un oggetto si Per una rappresentazione più carina di un oggetto si sovrascriva
sovrascriva toString toString : :
Questo funziona anche meglio: Questo funziona anche meglio:
public String toString() public String toString() { {
return "BankAccount[balance=" + balance + "]";
return "BankAccount[balance=" + balance + "]";
}}
BankAccount momsSavings = new BankAccount(5000);
BankAccount momsSavings = new BankAccount(5000);
String s = momsSavings.toString();
String s = momsSavings.toString();
// setta s a "BankAccount[balance=5000]"
// setta s a "BankAccount[balance=5000]"
67 67
Sovrascrivere il Metodo Sovrascrivere il Metodo
equals() equals()
equals equals testa l'uguaglianza del contenuto testa l'uguaglianza del contenuto
Figure 9:
Two References to Equal Objects
68 68
Sovrascrivere il Metodo Sovrascrivere il Metodo
equals() equals()
== == testa per l'uguaglianza della locazione testa per l'uguaglianza della locazione
Figure 10:
Two References to the Same Object
69 69
Sovrascrivere il Metodo Sovrascrivere il Metodo
equals() equals()
Definire il metodo Definire il metodo equals equals per testare se due per testare se due oggetti hanno un uguale stato
oggetti hanno un uguale stato
Nella ridefinizione del metodo Nella ridefinizione del metodo equals equals , non si può , non si può cambiare la firma; si può invece usare il cast:
cambiare la firma; si può invece usare il cast:
public class Coin public class Coin { {
. . . . . .
public boolean equals(Object otherObject) public boolean equals(Object otherObject) {
{
Coin other = (Coin) otherObject;
Coin other = (Coin) otherObject;
return name.equals(other.name) && value == other.value;
return name.equals(other.name) && value == other.value;
} }
. . . . . . }}
70 70
Sovrascrivere il Metodo Sovrascrivere il Metodo
equals() equals()
Si può anche sovrascrivere il metodo Si può anche sovrascrivere il metodo hashCode hashCode in modo che oggetti eguali abbiano lo stesso hash- in modo che oggetti eguali abbiano lo stesso hash-
code
code
71 71
Sovrascrivere il Metodo Sovrascrivere il Metodo
clone() clone()
Copiare un riferimento ad un oggetto risulta in due Copiare un riferimento ad un oggetto risulta in due riferimenti allo stesso oggetto
riferimenti allo stesso oggetto
BankAccount account2 = account;
BankAccount account2 = account;
72 72
Sovrascrivere il Metodo Sovrascrivere il Metodo
clone() clone()
Object 11:
Cloning Objects
A volte serve fare una copia dell'oggetto A volte serve fare una copia dell'oggetto
73 73
Sovrascrivere il Metodo Sovrascrivere il Metodo
clone() clone()
Si definisce il metodo Si definisce il metodo clone clone per creare un nuovo per creare un nuovo oggetto (cfr. argomenti avanzati 13.6)
oggetto (cfr. argomenti avanzati 13.6)
Uso di Uso di clone clone : :
Si deve fare un cast del valore ritornato perché il tipo Si deve fare un cast del valore ritornato perché il tipo di valore restituito da clone è semplicemente
di valore restituito da clone è semplicemente Object
Object
BankAccount clonedAccount = (BankAccount) account.clone();
BankAccount clonedAccount = (BankAccount) account.clone();