Programmazione Java Ereditarietà , Visibili - Giordano Tamburrelli ...
Programmazione Java Ereditarietà , Visibili - Giordano Tamburrelli ...
Programmazione Java Ereditarietà , Visibili - Giordano Tamburrelli ...
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Esercitazioni Ingegneria del So2ware <br />
2 -‐ <strong>Programmazione</strong> <strong>Java</strong> <br />
Ereditarietà, <strong>Visibili</strong>tà, Interfacce <br />
<strong>Giordano</strong> <strong>Tamburrelli</strong> <br />
tamburrelli@elet.polimi.it <br />
hFp://giordano.webfacIonal.com <br />
1
<strong>Java</strong>: Ereditarietà <br />
• Richiamo di teoria: <br />
• Una classe A dichiarata soFoclasse di un'altra classe B: <br />
– eredita (ha implicitamente) tuFe le variabili di istanza/aFribuI e tuR <br />
i metodi di B; <br />
– può avere variabili o metodi aggiunIvi; <br />
– può ridefinire i metodi ereditaI da B aFraverso l'overriding, in modo <br />
tale che essi eseguano la stessa operazione conceFuale in un modo <br />
specializzato. <br />
• In <strong>Java</strong> una classe A si dichiara soFoclasse di B scrivendo: <br />
– class A extends B<br />
2
<strong>Java</strong>: Ereditarietà <br />
• Esercizio: Modellizzare in <strong>Java</strong> le MountainBike. <br />
• Le MountainBike sono delle normali bicicleFe tuFavia nel loro <br />
stato interno hanno un valore intero che indica il livello <br />
dell’ammorIzzatore. <br />
• Soluzione 1: Quella che non vorreste mai implementare <br />
davanI al professore. <br />
• Soluzione 2: Quella correFa. <br />
3
<strong>Java</strong>: Ereditarietà <br />
• Esercizio: Modellizzare in <strong>Java</strong> le MountainBike. <br />
public class MountainBike {<br />
int cadence=0;<br />
int speed=0;<br />
int gear=1;<br />
int damperLv=1;<br />
void changeDamperLevel(int newValue){<br />
damperLv=newValue;<br />
}<br />
Ho copiato e incollato il 90% <br />
del codice della bicicleFa. E se <br />
la definizione di bicicleFa <br />
dovesse cambiare? Dovrei <br />
cambiare MountainBike <br />
void changeCadence(int newValue) {…}<br />
void changeGear(int newValue) {…}<br />
void speedUp(int increment) {…}<br />
void applyBrakes(int decrement) {…}<br />
} <br />
void printStates() {…}<br />
4
<strong>Java</strong>: Ereditarietà <br />
• Esercizio: Modellizzare in <strong>Java</strong> le MountainBike. <br />
public class MountainBike extends Bicycle{<br />
int damperLv = 1;<br />
} <br />
void changeDamperLevel(int newValue){<br />
damperLv=newValue;<br />
}<br />
• La keywork extends definisce che la MountainBike è una <br />
bicicleFa. Ha pertanto gli stessi campi interni e gli stessi <br />
metodi. <br />
• In aggiunta a una normale bicicleFa ha un livello di <br />
ammorIzzazione e un metodo che mi permeFe di cambiare <br />
tale livello. <br />
5
<strong>Java</strong>: Ereditarietà <br />
• Esercizio: Cosa stampa? <br />
class MountainBikeDemo {<br />
public static void main(String[] args) {<br />
}<br />
Bicycle bike1 = new Bicycle();<br />
Bicycle bike2 = new MountainBike();<br />
/*<br />
* Testiamo<br />
*/<br />
bike1.changeCadence(50);<br />
bike1.speedUp(10);<br />
bike1.changeGear(2);<br />
bike1.printStates();<br />
bike2.changeCadence(40);<br />
bike2.speedUp(10);<br />
bike2.changeGear(3);<br />
bike2.changeDamperLevel(2);<br />
bike2.printStates();<br />
Errore: <br />
L’oggeFo bike2 è stato <br />
dichiarato come Bicycle. <br />
Pertanto non possiede il metodo <br />
changeDamperLevel. A run2me <br />
gli viene assegnata una <br />
MountainBike. <br />
Soluzione 1: DowncasIng <br />
((MountainBike) <br />
bike2).changeDamperLevel(); <br />
Soluzione 2: Dichiarare come <br />
MountainBike se sappiamo che la <br />
useremo cosi. <br />
} <br />
6
<strong>Java</strong>: Ereditarietà <br />
• Esercizio: Cosa stampa? <br />
class MountainBikeDemo {<br />
public static void main(String[] args) {<br />
}<br />
Bicycle bike1 = new Bicycle();<br />
MountainBike bike2 = new Bicycle();<br />
/*<br />
* Testiamo<br />
*/<br />
bike1.changeCadence(50);<br />
bike1.speedUp(10);<br />
bike1.changeGear(2);<br />
bike1.printStates();<br />
bike2.changeCadence(40);<br />
bike2.speedUp(10);<br />
bike2.changeGear(3);<br />
bike2.changeDamperLevel(2);<br />
bike2.printStates();<br />
Errore: <br />
L’oggeFo bike2 è dichiarato <br />
come MountainBike. Pertanto <br />
deve essere garanIto che offrirà <br />
tuR i servizi di una <br />
MountainBike. Se gli assegnate <br />
una istanza di bicicleFa semplice <br />
non potrà offrire il servizio di <br />
changeDamperLevel(); <br />
Soluzione: <br />
MountainBike bike2=new MountainBike(); <br />
} <br />
7
<strong>Java</strong>: Ereditarietà <br />
• Esercizio: Cosa stampa? <br />
class MountainBikeDemo {<br />
public static void main(String[] args) {<br />
Stampa: <br />
}<br />
Bicycle bike1 = new Bicycle();<br />
MountainBike bike2 = new MountainBike();<br />
/*<br />
* Testiamo<br />
*/<br />
bike1.changeCadence(50);<br />
bike1.speedUp(10);<br />
bike1.changeGear(2);<br />
bike1.printStates();<br />
bike2.changeCadence(40);<br />
bike2.speedUp(10);<br />
bike2.changeGear(3);<br />
bike2.changeDamperLevel(2);<br />
bike2.printStates();<br />
La stampa della MountainBike è <br />
idenIca alla stampa della Bicycle. <br />
CorreFo, in quanto non abbiamo <br />
toccato il metodo printStates(). <br />
Ci interesserebbe però che <br />
quando richiamiamo printStates() <br />
su una MountainBike ci venisse <br />
stampata anche l’informazione <br />
sul livello dell’ammorIzzatore. <br />
} <br />
8
<strong>Java</strong>: Overriding <br />
• Richiamo di teoria: <br />
• L’overriding permeFe a una determinata soFoclasse di <br />
ridefinire una determinata implementazione di un metodo <br />
che è già presente in una delle sue superclassi. <br />
• L’implementazione nella soFoclasse overrides (sosItuisce) <br />
l’implementazione della superclasse. <br />
– Questo significa che quando andremo a invocare un metodo su un <br />
determinato oggeFo, il metodo che verrà effeRvamente eseguito <br />
dipende dall’oggeFo sul quale lo sIamo invocando. <br />
• In <strong>Java</strong> la soFoclasse deve definire un metodo con lo stesso <br />
nome, gli stessi parametri (nome e Ipo), e lo stesso Ipo di <br />
ritorno (o soFoIpo). <br />
9
<strong>Java</strong>: Overriding <br />
• Esercizio: Ridefinire il metodo printStates di MountainBike. <br />
public class MountainBike extends Bicycle{<br />
int damperLv = 1;<br />
void changeDamperLevel(int newValue){<br />
damperLv=newValue;<br />
}<br />
Poiché printStates() ha la <br />
stessa testata di quella che <br />
troviamo nella classe padre <br />
questa definizione sosItuisce <br />
quella di Bicycle. <br />
} <br />
void printStates() {<br />
System.out.println("cadence:"+cadence<br />
+”speed:"+speed<br />
+" gear:"+gear<br />
+"damperLevel:“+damperLv);<br />
}<br />
10
<strong>Java</strong>: Overriding <br />
• Esercizio: Ridefinire il metodo printStates di MountainBike <br />
(migliorato) <br />
public class MountainBike extends Bicycle{<br />
int damperLv = 1;<br />
void changeDamperLevel(int newValue){<br />
damperLv=newValue;<br />
}<br />
Se un determinato metodo fa <br />
overriding allora è possibile <br />
richiamare il metodo che state <br />
ridefinendo mediante la <br />
keyword super. <br />
} <br />
void printStates(){<br />
super.printStates();<br />
System.out.println("and damperLevel:“<br />
+damperLv);<br />
}<br />
Il vantaggio è di poter quindi <br />
estendere il metodo che state <br />
ridefinendo. <br />
11
<strong>Java</strong>: super vs this <br />
• Esercizio: Date le seguenI definizioni di classe… <br />
class Persona{<br />
String nome;<br />
String cognome;<br />
Persona(){<br />
nome="Sconosciuto";<br />
cognome="Sconosciuto";<br />
}<br />
Persona(String nome, String cognome){<br />
this.nome=nome;<br />
this.cognome=cognome;<br />
}<br />
class Studente extends Persona{<br />
int matricola;<br />
Studente(int matricola){<br />
//super()<br />
this.matricola=matricola;<br />
}<br />
Studente(String nome, String cognome, int<br />
matricola){<br />
super(nome, cognome);<br />
this(matricola);<br />
}<br />
void miPresento(){<br />
System.out.println(<br />
"Mi chiamo " + nome + " " +<br />
cognome);<br />
}<br />
}<br />
} <br />
void miPresentoStudente(){<br />
super.miPresento();<br />
this.miPresento();<br />
}<br />
void miPresento(){<br />
System.out.println(<br />
"Sono uno studente con matricola "<br />
+ matricola + ". ");<br />
}<br />
12
<strong>Java</strong>: super vs this <br />
• Esercizio: …cosa stampa? <br />
public class SuperAndThis {<br />
public static void main(String[] args){<br />
}<br />
}<br />
Persona p=new Persona("Alfredo", "Motta");<br />
p.miPresento();<br />
Studente s=new Studente("Alfredo", "Motta", 123);<br />
s.miPresento();<br />
Studente t=new Studente(123);<br />
t.miPresento();<br />
Stampa: <br />
Mi chiamo Alfredo MoFa <br />
Mi chiamo Alfredo MoFa <br />
Sono uno studente con matricola 123. <br />
Mi chiamo Sconosciuto Sconosciuto <br />
Sono uno studente con matricola 123. <br />
13
<strong>Java</strong>: Overriding vs Overloading <br />
class Super{...}<br />
class B extends A{<br />
class Sub extends Super{...}<br />
class A{<br />
public Super f1(int a){...}<br />
protected void f2(Super a){...}<br />
}<br />
public Object f1(int a){...}<br />
//errore: Object è ancestor di Super<br />
//Il tipo di ritorno deve essere un sottotipo di quello usato dal padre. Perché?<br />
public Super f1(long a){...}<br />
//overloading: Cambia il tipo dei parametri<br />
public Super f1(int a, int b){...}<br />
//overloading: Cambia il numero dei parametri<br />
public Sub f1(int a){...}<br />
//overriding: Valido perchè Sub è figlia di Super<br />
private Sub f1(int a){...}<br />
//errore: Non posso diminuire la visibilità quando faccio overriding<br />
//posso solo aumentarla<br />
protected void f2(Sub a){...}<br />
//overloading: anche se Sub è figlio di Super non stiamo ridefinendo f2<br />
public void f2(Super a){...}<br />
//overriding: la visibilità passa da protected a public. Nessun problema.<br />
} <br />
14
<strong>Java</strong>: Overriding <br />
• Esercizio: Creare una classe PrivateOverride con un metodo <br />
privato f(). Successivamente dichiarare la classe Derived <br />
soFoclasse di PrivateOverride avente metodo pubblico f(). <br />
• Discutere il problema dell’overriding del metodo privato f() di <br />
PrivateOverride da parte del metodo pubblico f() di Derived. <br />
15
<strong>Java</strong>: Overriding <br />
public class PrivateOverride {<br />
}<br />
private void f() { print("private f()"); }<br />
public static void main(String[] args) {<br />
PrivateOverride po = new Derived();<br />
po.f();<br />
}<br />
class Derived extends PrivateOverride {<br />
I metodi privaI sono <br />
automaIcamente di Ipo final <br />
pertanto non sarà possibile in <br />
nessun modo fare overriding di <br />
tali metodi. <br />
In questo esempio il <br />
programma stampa <br />
public void f() { print("public f()"); }<br />
private f() <br />
} <br />
Dichiarando la variabile po come <br />
Derived avremmo invece in output <br />
private f() <br />
16
<strong>Java</strong>: Overriding <br />
• Esercizio: Cosa stampa il seguente programma <br />
class Super {<br />
public int field = 0;<br />
public int getField() { return field; }<br />
}<br />
Stampa <br />
sup.field = 0, sup.getField() = 1 <br />
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0 <br />
class Sub extends Super {<br />
public int field = 1;<br />
public int getField() { return field; }<br />
public int getSuperField() { return super.field; }<br />
}<br />
class FieldAccess {<br />
public static void main(String[] args) {<br />
Super sup = new Sub(); // Upcast<br />
System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField());<br />
Sub sub = new Sub();<br />
System.out.println("sub.field = " + sub.field +<br />
", sub.getField() = " + sub.getField() +<br />
", sub.getSuperField() = " + sub.getSuperField()) ;<br />
}<br />
} <br />
17
<strong>Java</strong>: Polimorfismo <br />
• Richiamo di teoria: <br />
• il polimorfismo è una proprietà del codice in grado di <br />
comportarsi diversamente in diversi contesI di esecuzione. <br />
• Nella programmazione orientata agli oggeR il polimorfismo è <br />
legato alle relazioni di eredità tra classi. <br />
• L’overriding appena visto rende possibile che gli oggeR <br />
appartenenI a delle soFoclassi di una stessa classe <br />
rispondano diversamente alle stesse istruzioni. <br />
• Il duck typing (che non esiste in <strong>Java</strong> ma esiste in linguaggi <br />
come Ruby e Python è un esempio estremo di polimorfismo. <br />
18
<strong>Java</strong>: Polimorfismo <br />
• Esercizio: Le Figure si dividono in Cerchi, QuadraI e Triangoli. <br />
Ogni figura meFe a disposizione i metodi draw() e erase() per <br />
rispeRvamente stampare e cancellare la figura. <br />
• IpoIzzando che draw() e erase() stampino semplicemente <br />
delle stringhe che riportano l’operazione che si sta <br />
eseguendo, modellizzare la gerarchia di classi che discende da <br />
Figura. <br />
19
<strong>Java</strong>: Polimorfismo <br />
public class Shape {<br />
public void draw() {}<br />
public void eraseO {}<br />
Molto semplice, ci serve per <br />
svolgere i prossimi 2 esercizi. <br />
}<br />
public class Circle extends Shape {<br />
}<br />
public void draw() { System.out.println("Circle.draw()"); }<br />
public void erase() {System.out.println("Circle.erase() ") ; }<br />
public class Square extends Shape {<br />
}<br />
public void draw() {System.out.println("Square.draw()"); }<br />
public void erase() {System.out.println("Square.erase() ") ; }<br />
public class Triangle extends Shape {<br />
}<br />
public void draw() {System.out.println("Triangle.draw()"); }<br />
public void erase() {System.out.println("Triangle.erase() ") ; }<br />
20
<strong>Java</strong>: Polimorfismo <br />
• Esercizio: Creare una classe RandomShapeGenerator che <br />
mediante un metodo next() ritorni in modo random <br />
un’istanza di Circle, Square o Triangolo. <br />
public class RandomShapeGenerator {<br />
private Random rand = new Random(47);<br />
public Shape next() {<br />
switch(rand.nextlnt (3)) {<br />
default:<br />
case 0: return new Circle();<br />
case 1: return new Square();<br />
case 2: return new Triangle();<br />
}<br />
}<br />
UIlizziamo la classe Random <br />
offerta da <strong>Java</strong>, inizializzata con <br />
un opportuno seed. Andare a <br />
guardare la <strong>Java</strong> <br />
documentaIon per ulteriori <br />
deFagli. <br />
} <br />
21
<strong>Java</strong>: Polimorfismo <br />
• Esercizio: UIlizzando la classe RandomShapeGenerator creare <br />
un metodo main che mi permeFa di disegnare delle figure <br />
generate casualmente. <br />
public class Shapes {<br />
private static RandomShapeGenerator gen = new RandomShapeGenerator();<br />
} <br />
public static void main(String[] args) {<br />
Shape[] s = new Shape[9];<br />
// Fill up the array with shapes:<br />
for(int i = 0 ; i < s.length; i++)<br />
s[i] = gen.next() ;<br />
// Make polymorphic method calls:<br />
for(Shape shp : s)<br />
shp.draw();<br />
}<br />
22
<strong>Java</strong>: Polimorfismo <br />
• Esercizio: UIlizzando la classe RandomShapeGenerator creare <br />
un metodo main che mi permeFa di disegnare delle figure <br />
generate casualmente. <br />
public class Shapes {<br />
private static RandomShapeGenerator gen = new RandomShapeGenerator();<br />
} <br />
public static void main(String[] args) {<br />
Shape[] s = new Shape[9];<br />
// Fill up the array with shapes:<br />
for(int i = 0 ; i < s.length; i++)<br />
s[i] = gen.next() ;<br />
// Make polymorphic method calls:<br />
for(Shape shp : s)<br />
shp.draw();<br />
}<br />
StaIcamente a livello di codice <br />
io ho deciso di disegnare delle <br />
figure, tuFavia a run-‐Ime il <br />
metodo draw() cambia a <br />
seconda del Ipo dinamico che <br />
sIamo considerando. <br />
L’output di questo programma <br />
è “impredicibile” <br />
23
<strong>Java</strong>: Polimorfismo <br />
• Esercizio: Cosa stampa? <br />
class A{<br />
void f1(){<br />
System.out.println("f1InA()");<br />
}<br />
void f1(int a){<br />
System.out.println("f1InA(int a)");<br />
}<br />
void f2(){<br />
System.out.println("f2inA()");<br />
}<br />
}<br />
class B extends A{<br />
void f1(int b){<br />
System.out.println("f1InB(int b)");<br />
}<br />
}<br />
class D extends B{<br />
void f1(){<br />
System.out.println("f1InD()");<br />
}<br />
}<br />
class C extends A{<br />
void f1(char c){<br />
System.out.println("f1InC(char c)");<br />
}<br />
} <br />
public class Polimorphism {<br />
} <br />
public static void main(String[] args){<br />
}<br />
A St_A___Dy_D=new D();<br />
B St_B___Dy_C=new C();<br />
B St_B___Dy_D=new D();<br />
St_A___Dy_D.f1();<br />
St_A___Dy_D.f1(2);<br />
St_B___Dy_C.f1('c');<br />
St_B___Dy_D.f2();<br />
Stampa: f1InD() <br />
Stampa: f1InB(int b) <br />
… <br />
Stampa: f2InA() <br />
B <br />
D <br />
A <br />
C <br />
24
<strong>Java</strong>: Polimorfismo <br />
• Esercizio: Cosa stampa? <br />
public class Polimorphism5 {<br />
}<br />
public static void main(String[] args){<br />
}<br />
Scarpa s=new Scarpa();<br />
s.stampa();<br />
Scarpa g=new ScarpaDaGinnastica();<br />
g.stampa();<br />
class Scarpa{<br />
static void stampa(){<br />
System.out.println("Scarpa");<br />
}<br />
Stampa: <br />
Scarpa <br />
Scarpa <br />
Non è possibile fare overriding di un <br />
metodo staIco. <br />
In altre parole Il binding dinamico dei <br />
metodi esiste solo per quelli non-staIci.<br />
<br />
Se avessimo dichiarato g come <br />
ScarpaDaGinnasIca in quel caso il <br />
metodo stampa() avrebbe dato come <br />
output “Scarpa da ginnasIca” <br />
}<br />
class ScarpaDaGinnastica extends Scarpa{<br />
} <br />
static void stampa(){<br />
System.out.println("Scarpa da ginnastica");<br />
}<br />
25
<strong>Java</strong>: <strong>Visibili</strong>tà <br />
• Richiamo di teoria: Le keyword di visibilità si possono <br />
applicare alle classi, agli aFribuI e ai metodi. <br />
• Una classe può essere: <br />
– public: la classe è visibile a tuR <br />
– package-‐private: la classe è visibile solo all’interno del suo package. E’ <br />
il valore di default quando non si specifica nessuna visibilità. <br />
• AFribuI e metodi possono essere: <br />
– public, private, protected, package-‐private <br />
– Anche qui se viene omesso si intende package-‐private <br />
26
<strong>Java</strong>: <strong>Visibili</strong>tà <br />
La prima colonna ci dice che la classe può <br />
sempre accedere ai suoi membri <br />
indipendentemente dal livello di accesso. <br />
La seconda colonna ci dice i permessi <br />
relaIvi alle classi dichiarate nello stesso <br />
package (indipendentemente dalla <br />
parantela) <br />
La terza colonna ci dice i permessi relaIvi <br />
alle soFoclassi dichiarate in altri package. <br />
L’ulIma colonna ci dice i permessi del <br />
mondo esterno. <br />
27
<strong>Java</strong>: <strong>Visibili</strong>tà <br />
• Esercizio: Visibile? <br />
package Prova;<br />
public class A<br />
{<br />
private int private_int = 1;<br />
int package_int = 2;<br />
protected int protected_int = 3;<br />
public int public_int = 4;<br />
private void privateMethod() { ... }<br />
void packageMethod(){ ... }<br />
protected void protectedMethod(){...}<br />
public void publicMethod(){...}<br />
public static void main(String[] args)<br />
{<br />
A a = new A (); // Crea un oggetto di classe A<br />
a.privateMethod();<br />
a.packageMethod();<br />
a.protectedMethod();<br />
a.publicMethod();<br />
} <br />
System.out.println("private_int: " + a.private_int);<br />
System.out.println("package_int: " + a.package_int);<br />
System.out.println("protected_int: " + a.protected_int);<br />
System.out.println("public_int: " + a.public_int); }<br />
…<br />
Nessun errore: Dall’interno della classe posso <br />
sempre accedere a qualsiasi aFributo/metodo, <br />
indipendentemente dalla sua visibilità <br />
28
<strong>Java</strong>: <strong>Visibili</strong>tà <br />
• Esercizio: Visibile? <br />
package Prova;<br />
public class B<br />
{<br />
public static void main(String[] args)<br />
{<br />
A a = new A();<br />
a.privateMethod();<br />
a.packageMethod();<br />
a.protectedMethod();<br />
a.publicMethod();<br />
Il metodo privato non è <br />
visibile da una classe esterna. <br />
System.out.println("private_int: " + a.private_int);<br />
System.out.println("package_int: " + a.package_int);<br />
System.out.println("protected_int: " + a.protected_int);<br />
System.out.println("public_int: " + a.public_int);<br />
}<br />
} <br />
L’aFributo privato <br />
non è visibile a una <br />
classe esterna. <br />
29
<strong>Java</strong>: <strong>Visibili</strong>tà <br />
package ProvaB;<br />
import Prova.*;<br />
public class C extends A<br />
{<br />
public static void main(String[] args)<br />
{<br />
A a = new A();<br />
a.privateMethod();<br />
a.packageMethod();<br />
System.out.println("private_int: " + a.private_int);<br />
System.out.println("package_int: " + a.package_int);<br />
Sono fuori dalla classe e dal package <br />
a.publicMethod();<br />
System.out.println("public_int " + a.public_int);<br />
a.protectedMethod();<br />
System.out.println("protected_int: "+ a.protected_int);<br />
C c = new C();<br />
c.protectedMethod();<br />
System.out.println("protected_int: " + c. protected_int);<br />
}<br />
} <br />
E’ consenIto ad una istanza di <br />
una classe figlia far riferimento <br />
ai metodi e alle proprietà <br />
implementate nella classe padre <br />
ma non è permesso accedere ad <br />
essi aFraverso una istanza della <br />
classe padre. <br />
30
<strong>Java</strong>: <strong>Visibili</strong>tà <br />
• Esercizio: Date le seguenI classi <br />
public class O1 {<br />
private O2 o2=new O2();<br />
public O2 getO2(){<br />
return o2;<br />
}<br />
public class O2 {<br />
} <br />
public String nome;<br />
public void stampa(){<br />
System.out.println(o2.nome);<br />
}<br />
} <br />
• Posso modificare dall’esterno lo stato di O1? <br />
31
<strong>Java</strong>: <strong>Visibili</strong>tà <br />
• Soluzione: Certo che posso. Basta accedere ad o2 che è <br />
l’unico aFributo di O1 e modificarlo. <br />
public static void main(String[] args){<br />
O1 o1=new O1();<br />
} <br />
O2 o2=o1.getO2();<br />
o2.nome="ciao";<br />
o1.stampa();<br />
• L’inconveniente nasce dal faFo che O2 dichiara il suo <br />
aFributo come pubblico. Una volta oFenuto un riferimento <br />
all’aFributo di O1 posso modificarlo e O1 vedrà queste <br />
modifiche. <br />
32
<strong>Java</strong>: Interface <br />
• Esercizio: Modellizzare in <strong>Java</strong> un’applicazione in cui le <br />
Persone si suddividono in StudenI e Lavoratori <br />
• Possono esistere Persone semplici, StudenI, Lavoratori, ma <br />
anche degli StudenILavoratori. <br />
33
<strong>Java</strong>: Interface <br />
• Prima (pessima) idea <br />
public class Persona{<br />
}<br />
String nome;<br />
String getNome(){<br />
return nome;<br />
}<br />
public class Studente extends Persona{<br />
public class StudenteLavoratore extends<br />
Lavoratore{<br />
} <br />
int matricola;<br />
int getMatricola(){<br />
return matricola;<br />
}<br />
}<br />
int matricola;<br />
int getMatricola(){<br />
return matricola;<br />
}<br />
In <strong>Java</strong> non esiste l’ereditarietà <br />
mulIpla, ovvero non è possibile avere <br />
più di una classe padre. Questo mi crea <br />
una serie di limitazioni (superabili). <br />
public class Lavoratore extends Persona{<br />
}<br />
float salario;<br />
float getSalario(){<br />
return salario;<br />
}<br />
Questa soluzione eredita il <br />
comportamento di Lavoratore ma mi <br />
costringe a ricopiare il codice di <br />
Studente. Decisamente poco pulito. <br />
34
<strong>Java</strong>: Interface <br />
• La soluzione è nell’uIlizzo delle interfacce. <strong>Java</strong> ammeFe la <br />
possibilità di implementare interfacce mulIple. <br />
• Definiamo quindi… <br />
public interface Persona {<br />
String getNome();<br />
}<br />
public interface Studente extends Persona {<br />
int getMatricola();<br />
}<br />
public interface Lavoratore extends Persona{<br />
float getSalario();<br />
}<br />
public class PersonaImpl implements Persona{<br />
private String nome;<br />
public PersonaImpl(String nome) {<br />
this.nome = nome;<br />
}<br />
public String getNome() {<br />
return nome;<br />
}<br />
} <br />
Le interfacce rappresentano un <br />
contraFo tra classi. <br />
Chi implementa una determinata <br />
interfaccia dovrà fornire una <br />
implementazione del metodo <br />
dichiarato nell’interfaccia stessa. <br />
In questo caso PersonaImpl meFe a <br />
disposizione il metodo getNome() che <br />
deve essere garanIto in accordo con <br />
l’interfaccia Persona. <br />
35
<strong>Java</strong>: Interface <br />
public class StudenteLavoratore extends PersonaImpl implements Studente, Lavoratore {<br />
private int matricola;<br />
private float salario;<br />
public StudenteLavoratore(String nome, int matricola, float salario) {<br />
super(nome);<br />
this.matricola = matricola;<br />
this.salario = salario;<br />
}<br />
public int getMatricola() { return matricola; }<br />
public float getSalario() { return salario; }<br />
} <br />
Lo StudenteLavoratore è una Persona, <br />
quindi può invocare il suo costruFore <br />
passando il suo nome. <br />
Lo StudenteLavoratore fornisce i servizi <br />
garanII dalle interfacce che <br />
implementa: Studente, Lavoratore <br />
Anche in questo caso sarò costreFo a ricopiare buona parte dell’implementazione di <br />
Studente dentro StudenteLavoratore. TuFavia qui è esplicitato sintaRcamente in <strong>Java</strong> il <br />
faFo che Studente fornisce tuR i servizi forniI da Studente e da Lavoratore. Molto più <br />
ordinato. <br />
36