Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
In Java questa relazione tra le classi viene resa con la keyword extends
che deve essere usata nella dichiarazione della classe:
class A extends B {
// ...
}
Implica che ogni istanza della classe A sarà anche di tipo B ed avrà a
disposizione tutti i metodi della classe B e nel suo stato saranno
presenti tutte le variabili che si trovano nella super classe B.
/** /**
* ColloInVendita è la classe "derivata"
* Collo è la classe "base"
*/
*/ public class ColloInVendita extends Collo {
public class Collo { // dati (oltre quelli di Collo)
// dati private int price;
this.x_size = xs; public ColloInVendita(int w, int xs, int ys, int zs, int price) {
// richiama il costruttore della classe base
this.y_size = ys;
super(w, xs, ys, zs);
this.z_size = zs;
this.price = price;
} }
public int getVolume() { public float getDeliveryCost() {
return x_size * y_size * z_size; return A0*weight + B0*getVolume() + C0*price;
} }
} }
E’ utile osservare come, nella dichiarazione di ColloInvendita, siano utilizzabili sia i metodi che i
campi (a patto che siano public o protected) della super-classe Collo, che possono essere
eventualmente prefissati con la keyword super, utile per eventuali disambiguazioni.
Una nota speciale merita il costruttore, infatti il costruttore della classe ColloInVendita (derivata)
deve essere in grado di costruire una istanza della classe Collo e quindi se per quest'ultima non è
previsto un costruttore 'default' (senza argomenti) la classe derivata lo dovrà chiamare
esplicitamente passandogli gli argomenti necessari con la sintassi super(...) che deve essere
obbligatoriamente il primo statement del costruttore della classe figlia.
Leggendo la dichiarazione della classe Collo, dove non compare la keyword extends, potrebbe
nascere la convinzione che questa classe non derivi da nessuna "super-class"; per la verità vale la
pena di osservare che in Java ogni classe deriva da almeno una classe genitrice che, se la
keyword extends viene omessa, è per default la classe java.lang.Object, dalla quale ogni oggetto
Java eredita, per esempio, i metodi hashCode(), getClass(), toString().
Incapsulamento
Definizione di Incapsulamento
Nei programmi Object Oriented si è soliti mettere in stretta relazione
tra loro un pezzo di informazione con il comportamento specifico che
agisce su tale informazione. Questo è ciò che abbiamo definito oggetto.
L'incapsulamento è proprio legato al concetto di "impacchettare" in un
oggetto i dati e le azioni che sono riconducibili ad un singolo
componente.
Un altro modo di guardare all'incapsulamento è quello di pensare a
suddividere un'applicazione in piccole parti (gli oggetti, appunto) che
raggruppano al loro interno alcune funzionalità.
Esempio pratico
Ad esempio, pensiamo ad un conto bancario. Le informazioni utili (le proprietà)
potranno essere rappresentate da: il numero di conto, il saldo, il nome del cliente,
l'indirizzo, il tipo di conto, il tasso di interesse e la data di apertura.
Come risultato, ogni modifica al sistema informatico della banca che implichi una
modifica ai conti correnti, potrà essere implementata semplicemente nell'oggetto
Conto.
Con buona probabilità, se saremo stati bravi, saremo riusciti ad individuare l'80 per cento
dei punti da modificare. Con l'utilizzo dell'incapsulamento sarà, invece, sufficiente
identificare l'oggetto che gestisce l'azione di prelevamento (ovvero l'oggetto Conto) ed
eseguire la modifica all'interno di esso, completando la variazione del sistema richiesta
senza intaccare tutto il resto del sistema stesso.
Come fare per effettuare correttamente l’incapsulamento?
Nel caso in cui parliamo di lati non decimali, possiamo implementare il metodo più
semplice che ci viene in mente, tipo:
public int plusMethod(int l1, int l2, int l3, int l4) {
return l1 + l2 + l3 + l4;
}
Overload dei metodi
Ma nel caso in cui andiamo ad operare su un oggetto Rettangolo che però ha tutti i lati decimali?
Ovviamente non possiamo utilizzare questo metodo bensì avremo bisogno di qualcosa simile a:
public double plusMethod(double l1, double l1, double l1, double l1){
return l1 + l2 + l3 + l4;
}
Poiché i 2 metodi hanno parametri diversi (4 int il primo, 4 double il secondo) Java è in grado di
capire, durante la compilazione (a "compile-time"), quale è il metodo che intendiamo utilizzare e
decidere quindi quale invocare.
Se il linguaggio non permettesse l'overloading (es. il C) potremmo comunque implementare i 2
metodi ma saremmo costretti a utilizzare per loro due nomi diversi (per esempio plusMethodInt e
plusMethodDouble) e ottenere lo stesso risultato, al costo però di commettere una, seppure piccola,
violazione del principio di incapsulamento avendo dovuto esplicitare nel nome di un messaggio
(metodo) alcune informazioni circa la sua implementazione, cosa che, se evitabile, è bene non fare.
Ridefinire i metodi ereditati (override o "Inclusion polymorphism")
public static void main(String[] args) { • La prima riga dell'output ci dice che è stato
B b = new B(); chiamato il metodo metodo così come
A a = new A(); implementato nella classe B e sia la variabile
B aa = new A(); // A è sottoclasse di B quindi è che l'istanza sono di tipo B.
// assegnabile a variabili di tipo B
int c;
c = b.metodo(5, 7); • Il secondo risultato indica che è stata utilizzata
System.out.println(c); l'implementazione data nella classe A, poiché
c = a.metodo(5, 7); sia la variabile che l'istanza sono di tipo A.
System.out.println(c);
c = aa.metodo(5, 7);
System.out.println(c);
• Il fatto che l'ultima riga di output sia -2 implica
}
invece che nonostante la variabile aa sia di
In console otteniamo: tipo B, l'oggetto ritornato dal costruttore A(),
12 benchè assegnabile a una variabile di tipo B,
-2 ha dentro di sé riferimenti ai metodi come
-2 definiti per la classe A.
Esercizi
1- Il gestore di un negozio associa a tutti i suoi Prodotti un codice a barre univoco, una descrizione sintetica del prodotto e il suo prezzo unitario.
Realizzare una classe Prodotti con le opportune variabili d'istanza e metodi get.
1a-Aggiungere alla classe Prodotti un metodo applicaSconto che modifica il prezzo del prodotto diminuendolo del 5%.
1b-Aggiungere alla classe Prodotti un'implementazione specifica dei metodi ereditati dalla classe Object.
2-Il gestore del negozio vuole fare una distinzione tra i prodotti Alimentari e quelli Non Alimentari . Ai prodotti Alimentari viene infatti associata
una data di scadenza (si veda la classe LocalDate), mentre a quelli Non Alimentari il materiale principale di cui sono fatti. Realizzare le sottoclassi
Alimentari e NonAlimentari estendendo opportunamente la classe Prodotti.
3-Modificare le due sottoclassi dell'esercizio 2 specializzando il metodo applicaSconto in modo che nel caso dei prodotti Alimentari venga
applicato uno sconto del 20% se la data di scadenza è a meno di 10 giorni dalla data attuale (si usi il metodo getDifference della classe Data),
mentre nel caso dei prodotti Non Alimentari venga applicato uno sconto del 10% se il prodotto è composto da un materiale riciclabile (carta, vetro
o plastica).
4-Realizzare una classe ListaSpesa che chieda all'utente di inserire i prodotti acquistati e calcoli il totale della spesa applicando gli opportuni sconti
se il cliente ha la tessera fedeltà.
Esercizi 2
• 1 Scrivere un programma Java che chiede all’utente di inserire due stringhe e
che visualizza all’utente true se le stringhe sono uguali e false se sono diverse.