08.03.2015 Views

Programmazione Java Ereditarietà, Visibili - Giordano Tamburrelli ...

Programmazione Java Ereditarietà, Visibili - Giordano Tamburrelli ...

Programmazione Java Ereditarietà, Visibili - Giordano Tamburrelli ...

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!