Docsity
Docsity

Prepara i tuoi esami
Prepara i tuoi esami

Studia grazie alle numerose risorse presenti su Docsity


Ottieni i punti per scaricare
Ottieni i punti per scaricare

Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium


Guide e consigli
Guide e consigli


Polimorfismo e Binding Dinamico in Java: Esercizi e Spiegazione, Appunti di Programmazione Java

Java appunti slide sulle proprieta di programmazione ad oggetti

Tipologia: Appunti

2018/2019

Caricato il 29/08/2019

francesco-pistorio
francesco-pistorio 🇮🇹

4.8

(8)

17 documenti

1 / 14

Toggle sidebar

Questa pagina non è visibile nell’anteprima

Non perderti parti importanti!

bg1
1
inheritance
à
casting
à
polimorfismo
a.a. 2018-2019
2
es. la classe Pixel estende la classe Point
class Point {
public double x, y;
public void clear() { this.x = 0.0; this.y = 0.0; }
public void move(double x, double y) {
this.x = x; this.y = y;
}
}
class Pixel extends Point {
Color color;
public void clear() {
super.clear();
color = null;
}
}
la classe Pixel estende sia la struttura dati (aggiunge il campo color) che il
comportamento (overriding del metodo clear) della superclasse Point
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe

Anteprima parziale del testo

Scarica Polimorfismo e Binding Dinamico in Java: Esercizi e Spiegazione e più Appunti in PDF di Programmazione Java solo su Docsity!

1

inheritance à casting à polimorfismo

a.a. 2018 - 2019

2

es. la classe Pixel estende la classe Point

class Point {

public double x, y;

public void clear() { this.x = 0.0; this.y = 0.0; }

public void move(double x, double y) {

this.x = x; this.y = y;

class Pixel extends Point {

Color color;

public void clear() {

super.clear();

color = null;

la classe Pixel estende sia la struttura dati (aggiunge il campo color) che il

comportamento (overriding del metodo clear) della superclasse Point

3

polimorfismo

polimorfismo : capacità di un oggetto di assumere forme molteplici

  • come oggetto della propria classe
  • come oggetto di qualunque classe che estenda la sua classe

● gli oggetti Pixel possono essere utilizzati da qualunque porzione

di codice progettata per lavorare con gli oggetti Point

  • se un metodo si aspetta un parametro di tipo Point gli si può

passare un oggetto Pixel e il metodo continua a funzionare

  • tutto il codice scritto per utilizzare oggetti Point può utilizzare

oggetti Pixel

Point pix = new Pixel();

pix.clear();

quale metodo è invocato?

la regola “is–a” à substitution principle

qualunque object della subclass è un object della superclass

● es ogni manager è un ( is-a ) employee.

  • ha senso perchè Manager è sottoclasse di Employee.
  • ovviamente l’opposto non vale : non tutti gli employee sono manager

● un altro modo di formulare la regola “is–a” è il substitution principle.

1. si può usare un subclass object ovunque si aspetta un superclass

object,

2. si può assegnare un subclass object ad una superclass variable.

● una variabile di tipo Employee può riferire un oggetto di qualunque tipo

subclasse di Employee, ad es. Manager, Executive, Secretary, ..

es.

Employee e;

e = new Employee(…); // Employee object expected

e = new Manager(…); // OK, Manager can be used as well

nota: in Java, le object variable sono polymorphic

7

upcasting

se

variabile x è di tipo T

espressione di tipo E

x = // ok!!!

x = (T) // permesso se col casting esplicito

T

E

x

downcasting

E

T

x

compatibilità di tipo e conversione

● I tipi più in alto nella gerarchia dei tipi si dice che siano più ampi

( wider ), o più generali, rispetto ai tipi più in basso nella gerarchia.

● I tipi più in basso si dice che siano più stretti (narrower), o più

specifici, rispetto ai loro supertipi.

cast verso l’alto – upcast - widening conversion

  • è un cast sicuro in quanto sempre valido

cast verso il basso – downcast - narrowing conversion

  • è un cast insicuro perchè a volte può non essere valido

9

upcasting

● Quando si è in attesa di un supertipo e si riceve un sottotipo,

avviene una conversione di ampliamento (widening

conversion/upcasting).

● la conversione upcasting fa sì che l' oggetto sottotipo sia trattato

come un'istanza del supertipo

  • può essere controllato al momento della compilazione.

● un upcasting è automatico e non occorre l’intervento del programmatore.

esempio precedente

staff[0] = boss;

Manager

Employee

10

downcasting

● dato un riferimento a un supertipo, la conversione in un riferimento a un

sottotipo è conosciuto come una conversione di restrizione (narrowing

conversion/downcasting).

Il downcast è un cast insicuro perchè a volte può non essere valido

  • richiede un casting esplicito nel codice in modo che il compilatore

accerti la fattibilità di questa conversion e la accetti

  • Non è detto che la conversione sia accettabile in fase di esecuzione

perchè l’oggetto effettivo a runtime potrebbe non avere le proprietà

specifiche della sottoclasse

Persona

Studente

Persona p; Studente s;

p = s; // ok: assign compatibility

s = p; //noooo! occorre downcasting esplicito

s = (Studente) p; // downcasing esplicito:

// java lo permette ma è pericoloso

p

s

nota: il contratto di s è più ampio di quello di p ma p potrebbe davvero essere un

oggetto Studente quindi usabile correttamente come tale tipo

13

polimorfismo

public class Persona {

protected String nome;

protected int anni;

public Persona(String n) {nome = n; anni = 0; }

public Persona(String n, int a) {nome=n; anni=a; }

public void print() {

System.out.print(“mi chiamo " + nome);

System.out.println(" e ho " + anni + "anni");

public class Studente

extends Persona {

protected int matr;

public Studente() {super(); matr = 9999; } //funziona??

public Studente(String n) { super(n); matr = 8888 ; }

public Studente(String n, int a) { super(n,a); matr=7777; }

public Studente(String n, int a, int m) {

super(n,a); matr=m; }

public void print() {

super.print(); System.out.println("Matricola = " + matr);}

Persona

Studente

@Override

Ridefinisce il metodo void print() sovrascrive quello ereditato

da Persona

  • è una versione specializzata per Studente che però riusa quello

di Persona (super), estendendolo per stampare la matricola

14

esempio: la classe SocialTest

public class SocialTest {

public static void main(String args[]){

Persona p = new Persona(”Giovanni”….);

Studente s = new Studente("Tommaso”…);

p.print(); // stampa nome, anni

s.print(); // stampa nome, anni, matricola

p=s; // OK (upcasting: Studente estende Persona)

p.print(); // COSA STAMPA ???

L’assegnamento p=s non comporta perdita di

informazione, perché si assegnano riferimenti (gli

oggetti puntati rimangono inalterati)

problema: cosa stampa?

  • p è un riferimento a

Persona

  • ma gli è stato assegnato

un oggetto Studente

  • Se prevale la natura del riferimento, stamperà solo nome ed età
  • Se prevale la natura dell’oggetto puntato , stamperà nome, età e matricola

È un problema di POLIMORFISMO

esempio

semplificato

15

polimorfismo

Un metodo si dice polimorfo quando è in grado di adattare il suo

comportamento allo specifico oggetto su cui deve operare.

● In Java, la possibilità di usare riferimenti a una data classe - es., Persona

per puntare a oggetti di classi più specifiche – es. Studente

introduce in astratto la possibilità di avere polimorfismo.

Ma in pratica?

….. dipende cosa prevale:

● se prevalesse il tipo del riferimento, non ci sarebbe mai polimorfismo

  • in tal caso, p.print() stamperebbe solo nome ed età, perché

viene invocato il metodo print() della classe Persona

● se invece prevale il tipo dell’oggetto,

allora c’è polimorfismo

  • in tal caso, p.print() stamperà nome, età e matricola, perché

verrà invocato il metodo print() della classe Studente

Java supporta il Polimorfismo

® prevale il tipo dell’oggetto

void print() è un metodo polimorfo è

poiché p referenzia uno Studente,

stampa nome, data di nascita, matricola cdl

OOP

16

early binding e late binding

● Il programmatore del client non ha bisogno di sapere quale frammento

di codice verrà eseguito à

● il compilatore non può sapere al momento della compilazione

quale frammento di codice verrà eseguito

  • Il compilatore non può operare il tradizionale early/static binding
  • Tipicamente l’OOP utilizza il late/dynamic binding : quando si

invia un messaggio ad un oggetto, il codice che viene chiamato

non è determinato (non se ne conosce l’indirizzo esatto) fino al

momento dell’esecuzione

● Il compilatore garantisce che il metodo esiste, esegue il controllo

sugli argomenti e sul valore ritornato ma non conosce l’esatto

codice da eseguire

● in Java il dynamic binding è di default

LATE BINDING: le chiamate ai metodi sono collegate alla versione

opportuna del metodo al momento della chiamata , in base

all’oggetto effettivamente referenziato (a “run-time”)

19

…ma più classi possono derivare da una classe base comune

● Nella programmazione ad oggetti, il polimorfismo indica il fatto che lo stesso

codice eseguibile può essere utilizzato con istanze di classi diverse, aventi

una superclasse comune

● Il polimorfismo è particolarmente utile quando il linguaggio supporta il binding

dinamico (o late-binding):

  • la versione del metodo da eseguire viene scelta sulla base del tipo di

oggetto effettivamente contenuto in una variabile a runtime

● non a compile time

● Se una variabile di tipo A ha due sottotipi (sottoclassi) B e C , che ridefiniscono

entrambe il metodo m() , l'oggetto contenuto nella variabile potrà essere di

tipo A , B o C , e quando sulla variabile viene invocato il metodo m() viene

eseguita la versione appropriata per il tipo di oggetto contenuto nella variabile

in quel momento.

A

C

B

La funzionalità binding

dinamico (o late-binding) è

supportata dai più diffusi

linguaggi di programmazione ad

oggetti.

esempio

class Animale {

public void verso () {

System.out.println(”sono un Animale"); }

class Pesce extends Animale {

public void verso() {

System.out.println(”glug glug");}

class Uccello extends Animale {

public void verso() {

System.out.println(”tweet tweet"); }

class Cane extends Animale {

public void verso() {

System.out.println(“woof woof"); }

public void ringhia() { System.out.println("Arf Arf"); }

tanto per dire che “un animale avrà un verso” L

non certo per scrivere un codice che valga nelle

varie classi derivate!!

21

public class Zoo {

public static void main (String[ ] argv) {

Animale[] animali = new Animale[3];

int index;

animali [0] = new Uccello( );

animali [1] = new Cane( );

animali [2] = new Pesce( );

for (Animale animale : animali)

animale.verso();

● La classe Animale ha verso() cosi ogni membro della classe può fare un

verso

● Output di un System.out.print…….

  • Tweet tweet
  • woof woof
  • Glug glug

Polimorfismo e Dynamic Binding

Polimorfismo significa “assume molte forme”.. un riferimento a

una data classe può prendere la forma [oggetto concreto

riferito] di ognuna delle sue sottoclassi.

● Polimorfismo e Dynamic Binding insieme assicurano il corretto

funzionamento del metodo verso() dell’esempio precedente.

● Un oggetto di una sottoclasse può sostituire un oggetto della superclasse:

“un uccello è un animale”

● Il contrario non vero: non si può sostituire un oggetto di una

sottoclasse con uno della superclass “un Animale non un è un uccello”.

● Abbiamo una singola interfaccia per un comportamento multiplo:

  • Solo una interfaccia per la chiamata del metodo.
  • Comportamento multiplo basato sulla sottoclasse

25

un esempio di utilizzo di downcasting

public class provaDownCasting{

public static void main(String[ ] argv) {

Animale[] zoo = new Animale[3];

zoo[0] = new Uccello( );

zoo[1] = new Cane( );

zoo[2] = new Pesce( );

for (Animale animale : zoo) {

animale.verso();

if (animale instanceof Cane){

Cane c = (Cane) animale;

c.ringhia();

La classe Animale ha verso() è ogni oggetto di zoo fa un verso

uso di instanceof

● Il Casting è usato qui per dare ad un oggetto di una sottoclasse la forma della

sottoclasse appropriata per consentire la chiamata del metodo;

infatti l’invocazione:

animale.ringhia ();

produce un errore perché un oggetto della classe Animali non ha il metodo

ringhia().

● Cosi, prima occorre eseguire il casting

if (animale instanceof Cane) {

Cane c = (Cane) animale;

c.ringhia();

● ma se Java può determinare cos’è o non è una dato oggetto attraverso di

instanceof, perché è necessario il cast?

Perche Java non fa questo per noi?

attenzione!!! errore!!!

27

if (animale instanceof Cane){

animale.ringhia(); //NOOO!

● La prima riga è corretta, la seconda no a meno che animale non sia

dichiarato di elementi Cane

  • Il compilatore non vede il legame fra le istruzioni,
  • il runtime system può vederlo, ma per garantire le performance non

sono effettuate queste verifiche durante la compilazione, lasciando

al programmatore il compito del controllo per non provocare errore :

if (animale instanceof Cane) {

Cane c = (Cane) animale;

c.ringhia( );

à casting, polimorfismo e binding dinamico sono legati

● Quando chiamiamo un metodo su un riferimento, il metodo deve

esistere (o essere ereditato) nel tipo.

● Comunque, la specifica implementazione e determinata a runtime,

  • cioè utilizzando il “dynamic bynding”

● Errori a Compiletime:

● Quelli che sono rilevabili senza che il programma sia un esecuzione

  • Istruzione certamente illegale
  • es:

Employee e = new Manager(…);

e.getBonus(); // NOO!! il compilatore non accetta un downcasting implicito

Animale animale = new Animale(); // oppure new Uccello()…

animale.ringhia(); // NOO!! il il compilatore non accetta un downcasting

implicito

● Errori a Run-time:

● Quelli che sono riconoscibili solo durante l’esecuzione con i valori reali.

● Es.

Employee e = new Employee(…);

(Manager)e.getBonus() //NO: un Employee in genere non ha getBonus()

Animale animale = new Animale(); //oppure new Uccello()…

(Cane)animale.ringhia(); // NO: un Animale in genere non ha ringhia()