Pagina Iniziale | Preferiti Comunity: Login | Registrati | Newsletter | Forum | Concorsi Newsgroup
Canali: Hardware | Software | Files | Webmaster | Cellulari | Shop
Nel sito: News | Articoli | Files | Manuali | Consigli PC | Schede cellulari | Programmaz. | Hosting | Motori Ricerca | Glossario | Link
Servizi: Shopping | Forum | Crea un BLOG | Cartucce Compatibili | Tool News |   Sponsor: Automazione Industriale
  Articoli

Recensioni
Consigli per PC


  News e files

Software
Telefonia
Internet
Tecnologia
Files e Download


  Manualistica

Guide HW/SW
Scripts ASP
Scripts HTML
Scripts Java
Scripts Delphi
Glossario


  Shopping

Hardware
Software e Giochi
Elettronica
Cinema e Film
Console e Accessori
Prodotti Ufficio
Formazione e Corsi

Tieniti aggiornato sul mondo della tecnologia con la nostra newsletter!
La tecnologia sulla tua
casella e-mail

[Info Newsletter]


Concessionaria Pubblicitaria

<< News Precedente [Fine Pagina] News Successiva >>
Il linguaggio Java: lez.7

Un articolo di: Fonte Esterna del 28/12/2002      Letture: 18116
Vai alla pagina:
 1 - Introduzione e Unità didattica 6.1.1)

Si ringrazia Claudio De Sio per la concessione del materiale pubblicato in questo articolo.

Programmazione ad oggetti utilizzando Java:


Polimorfismo

Obiettivi:
Il Lettore al termine di questo capitolo dovrà essere in grado di
  • Comprendere il significato del polimorfismo (unità 6.1).
  • Saper utilizzare l’overload, l’override ed il polimorfismo per dati (unità 6.1).
  • Comprendere e saper utilizzare le collezioni eterogenee,i parametri polimorfi, ed i metodi virtuali (unità 6.1).
  • Sapere utilizzare l’operatore instanceof, ed il casting di oggetti (unità 6.1).



Unità didattica 6.1)

- Polimorfismo

Il polimorfismo (dal greco "molte forme") è un altro concetto che dalla realtà, è stato importato nella programmazione ad oggetti. Esso ci permette di riferirci con un unico termine a "entità" diverse. Ad esempio, sia un telefono fisso, sia un portatile ci permettono di telefonare, dato che entrambi i mezzi sono definibili come telefoni. Telefonare quindi, può essere considerata un’azione polimorfica (ha diverse implementazioni). Ma il polimorfismo in Java, è argomento complesso che si dirama in vari sotto-argomenti.

Utilizzando una convenzione con la quale rappresenteremo con rettangoli i concetti, e con ovali concetti che hanno una reale implementazione in Java, cercheremo di schematizzare il polimorfismo e le sue espressioni.

- Convenzione per i reference:

Prima di iniziare a definire i vari aspetti del polimorfismo, presentiamo una convenzione per la definizione di una variabile di tipo reference. Definire precisamente cosa sia un reference, e come sia rappresentato in memoria, non è cosa semplice. Di solito s’identifica un reference con un puntatore. In molti testi relativi ad altri linguaggi di programmazione, un puntatore viene definito come "una variabile che contiene un indirizzo". In realtà la definizione di puntatore cambia da piattaforma a piattaforma. Per convenzione possiamo definire un reference come una variabile che contiene due informazioni rilevanti: l’indirizzo in memoria, e l’intervallo di puntamento definito dalla relativa classe. Per esempio se scriviamo

  Punto ogg = new Punto();

possiamo supporre che il reference ogg abbia come indirizzo un valore numerico, ad esempio 10023823, e come intervallo di puntamento Punto. In particolare, ciò che abbiamo definito come intervallo di puntamento farà sì che il reference ogg possa accedere all’interfaccia pubblica della classe Punto, ovvero, a tutti i membri pubblici (x, y, distanzaDallOrigine) dichiarati nella classe Punto, tramite il reference ogg. L’indirizzo invece farà puntare il reference ad una particolare area di memoria dove risiederà il particolare oggetto istanziato. Di seguito viene riportato uno schema rappresentativo:


- Polimorfismo per metodi:

Il polimorfismo per metodi, per quanto detto sino ad ora, ci permetterà di utilizzare lo stesso nome per metodi differenti. In Java, esso trova una sua realizzazione pratica sotto due forme: l’overload (che potremmo tradurre con "sovraccarico") e l’override (che potremmo tradurre con "riscrittura"). - Overload:

Definizione 1:

In un metodo, la coppia costituita dall’identificatore e dalla lista dei parametri è detta "segnatura" o "firma" del metodo.

In Java, un metodo è univocamente determinato non solo dal suo identificatore, ma anche dalla sua lista di parametri, cioè dalla sua segnatura. Quindi, in una classe, possono convivere metodi con lo stesso nome, ma con differente firma. Su questo semplice concetto si fonda una delle caratteristiche più utili di Java: l’overload. Tramite esso il programmatore potrà utilizzare lo stesso nome per metodi diversi. Ovviamente tutto ciò deve avere un senso logico, un significato. Per esempio potremmo assegnare lo stesso nome a due metodi che concettualmente hanno la stessa funzionalità, ma che soddisfano tale funzionalità in maniera differente. Presentiamo di seguito, un banale esempio di overload:

class Aritmetica
{
  public int somma(int a, int b)
  {
    return a+b;
  }
  public float somma(int a, float b)
  {
    return a+b;
  }
  public float somma(float a, int b)
  {
    return a+b;
  }
  public int somma(int a, int b, int c)
  {
    return a+b+c;
  }
  public double somma(int a, double b, int c)
  {
    a+b+c;
  }
}

In questa classe ci sono ben cinque metodi che hanno lo stesso nome, svolgono delle somme, ma in modo differente. Se invece volessimo implementare questi metodi in un altro linguaggio che non supporta l’overload, dovremmo inventare un nome nuovo per ogni metodo. Presumibilmente il primo di essi si potrebbe chiamare "sommaDueInt", il secondo "sommaUnIntEUnFloat", il terzo "sommaUnFloatEUnInt", il quarto "sommaTreInt", il quinto addirittura "sommaUnIntUnDoubleEUnFloat"! A questo punto pensiamo sia evidente al lettore l’utilità dell’overload. Notiamo che la lista dei parametri ha tre criteri di distinzione:

tipale (Es.: somma(int a, int b) è diverso da somma(int a, float b))

numerico (Es.: somma(int a, int b) è diverso da somma(int a, int b, int c))

posizionale (Es.: somma(int a, int b) è diverso da somma(float a, int b))

Gli identificatori che utilizziamo per i parametri, non sono quindi criteri di distinzione per i metodi (Es.: somma(int a, int b) non è diverso da somma(int c, int d)).

N.B.: il tipo di ritorno non fa parte della firma di un metodo, quindi non ha importanza per l'argomento overload.

N.B.: In alcuni testi, l’overload non è considerato come aspetto polimorfico di un linguaggio. In questi testi il polimorfismo stesso è definito in maniera diversa da com’è stato definito in questo contesto. Come sempre, è tutto relativo all’ambito in cui ci si trova. Se ci fossimo trovati a discutere anziché di programmazione, di analisi e progettazione object oriented, probabilmente neanche noi avremmo inserito l’overload come argomento del polimorfismo.

- Override:

L’override, e questa volta non ci sono dubbi, è invece considerata una potentissima caratteristica della programmazione ad oggetti, ed è da qualcuno superficialmente identificato con il polimorfismo stesso. L’override (sovra-scrittura) è il termine object oriented che viene utilizzato per descrivere la caratteristica che hanno le sottoclassi, di ridefinire un metodo ereditato da una superclasse. Ovviamente, non esisterà override senza ereditarietà. Una sottoclasse non è mai meno specifica di una classe che estende, e quindi, potrebbe ereditare metodi che hanno bisogno di essere ridefiniti per funzionare correttamente nel nuovo contesto.

Ad esempio supponiamo che una classe Punto (che per convenzione assumiamo bidimensionale), dichiari un metodo DistanzaDallOrigine che calcola, con la nota espressione geometrica, la distanza tra un punto di determinate coordinate dall'origine degli assi cartesiani. Ovviamente questo metodo ereditato all’interno di un’eventuale classe PuntoTridimensionale ha bisogno di essere ridefinito per calcolare la distanza voluta, tenendo conto anche della terza coordinata. Vediamo quanto appena detto sotto forma di codice. Per semplicità il nostro codice non farà uso "dell’obbligatorio incapsulamento".

N.B.: il lettore è invitato a riflettere sulle discutibili scelte di chiamare una classe che astrae un punto bidimensionale "Punto", e di inserire il metodo DistanzaDallOrigine nella stessa classe. Non stiamo così violando il paradigma dell’astrazione?

class Punto
{
  public int x, y;
  public double distanzaDallOrigine()
  {
    int tmp=(x*x) + (y*y);
    return Math.sqrt(tmp);
  }
}
class PuntoTridimensionale extends Punto
{
  int z;
  public double distanzaDallOrigine()
  {
    int tmp=(x*x) + (y*y) + (z*z);
    return Math.sqrt(tmp);
  }
}     

N.B.: il metodo sqrt() della classe Math (package java.lang), restituisce un valore double risultato della radice quadrata del parametro passato (il lettore è invitato sempre e comunque a consultare la documentazione). E’ stato possibile invocarlo con la sintassi nomeClasse.nomeMetodo anziché nomeOggetto.nomeMetodo perché trattasi di un metodo statico. Discuteremo nel modulo 9 in dettaglio i metodi statici. Il lettore si accontenti per il momento di sapere che un metodo statico "appartiene alla classe".

Si può osservare come è stato possibile ridefinire il blocco di codice del metodo DistanzaDallOrigine, per introdurre le terza coordinata di cui tenere conto, affinché il calcolo della distanza sia eseguito correttamente nella classe PuntoTridimensionale.

È bene notare che ci sono delle regole da rispettare per l’override.

1) se decidiamo di riscrivere un metodo in una sottoclasse, dobbiamo utilizzare la stessa identica segnatura, altrimenti utilizzeremo un overload in luogo di un override.

2) il tipo di ritorno del metodo deve coincidere con quello del metodo che si sta riscrivendo.

3) il metodo ridefinito, non deve essere meno accessibile del metodo che ridefinisce. Per esempio se un metodo ereditato è dichiarato protetto, non si può ridefinire privato, ma semmai, pubblico.

- Override & classe Object: metodo toString()

Abbiamo detto che la classe Object è la superclasse di tutte le classi. Ciò significa che quando codificheremo una classe qualsiasi, erediteremo tutti gli 11 metodi di Object. Tra questi c’è il metodo toString() che avrebbe il compito di restituire una stringa descrittrice dell’oggetto. Nella classe Object, che astrae il concetto di oggetto generico, tale metodo non poteva adempiere questo scopo, giacché un’istanza della classe Object non ha variabili d’istanza che lo caratterizzano. E’ quindi stato deciso di implementare il metodo toString() in modo tale che restituisca una stringa contenente informazioni sul reference del tipo:

  nomeClasse@indirizzoInEsadecimale

che per la convenzione definita in precedenza potremmo interpretare come:

  intervalloDiPuntamento@indirizzoInEsadecimale

Per esercizio, il lettore può provare a stampare un reference qualsiasi.

Un altro metodo che degno di nota, è il metodo equals().Esso è destinato a confrontare tra due reference (sul primo è chiamato il metodo e il secondo viene passato come parametro), e restituisce un valore booleano true se e solo se i due reference puntano ad uno stesso oggetto. Ma questo tipo di confronto, come abbiamo avuto modo di costatare nel modulo 3, è fattibile anche mediante l’operatore "==". Allora, in molte sottoclassi di Object, come ad esempio String, il metodo equals() è stato riscritto in modo tale da restituire true anche nel caso di confronto tra due reference che puntano ad oggetti diversi, ma con gli stessi contenuti. È molto importante tenere conto di quanto appena detto, per non perdere ore preziose in debug evitabili.

- Polimorfismo per dati (per classi):

Il polimorfismo per dati, permette essenzialmente di poter assegnare un reference di una superclasse ad un’istanza di una sottoclasse. Per esempio, tenendo conto che PuntoTridimensionale è sottoclasse di Punto, sarà assolutamente legale scrivere:

  Punto ogg = new PuntoTridimensionale();

Il reference ogg, infatti, punterà ad un indirizzo che valida il suo intervallo di puntamento. Praticamente l’interfaccia pubblica dell’oggetto creato (costituita dalle variabili x, y e z) contiene l’interfaccia pubblica della classe Punto (costituita dalle variabili x e y), e così il reference ogg "penserà" di puntare ad un oggetto Punto. Se volessimo rappresentare graficamente questa situazione, potremmo basarci sulla seguente figura:

Questo tipo d’approccio ai dati ha però un limite. Un reference di una superclasse, non potrà accedere ai campi dichiarati per la prima volta nella sottoclasse. Nell’esempio otterremmo un errore in compilazione se tentassimo quindi di accedere alla terza coordinata Z del PuntoTridimensionale, tramite il reference ogg. In pratica, la codifica della seguente riga:

 ogg.z=5;

produrrebbe un errore in fase di compilazione, dal momento che ogg è un reference che ha un intervallo di puntamento di tipo Punto.

Il lettore è rimandato al termine di questo modulo per la conoscenza delle fondamentali conseguenze che tale approccio ai dati comporterà.

- Parametri polimorfi:

Sappiamo che i parametri in Java sono sempre passati per valore. Ciò implica che passare un parametro di tipo reference ad un metodo, significa passare il valore numerico del reference, in altre parole, il suo indirizzo. A quest’indirizzo potrebbe risiedere un oggetto istanziato da una sottoclasse, grazie al polimorfismo per dati.

In un metodo, un parametro di tipo reference, si dice polimorfo, quando, anche essendo di fatto un reference relativo ad una determinata classe, può puntare ad un oggetto istanziato da una sottoclasse. In pratica sfruttando il polimorfismo per dati, un parametro di un metodo potrebbe in realtà puntare ad oggetti diversi.

1)  public void stampaOggetto(Object ogg)
{
  System.out.println(ogg.toString());
}

Ora il lettore sa bene che tutte le classi sono sottoclassi di Object. Quindi potremmo chiamare il metodo stampaOggetto, passandogli come parametro anziché un’istanza di Object, un’istanza di String come "Ciao". Ma a questo tipo di metodo possiamo passare un’istanza di qualsiasi classe, dal momento che vale il polimorfismo per dati, ed ogni classe è sottoclasse di Object.

N.B.: ogni classe eredita dalla classe Object il metodo toString. Molte classi della libreria standard di Java fanno un override di questo metodo, restituendo stringhe descrittive dell’oggetto. Se al metodo stampaOggetto passassimo come parametro un oggetto di una classe che non ridefinisce il metodo toString, sarebbe chiamato il metodo toString ereditato dalla classe Object.

N.B.: il frammento di codice 1) è assolutamente equivalente al seguente:
2)  public void stampaOggetto(Object ogg)
{
  System.out.println(ogg);
}

infatti il metodo println utilizzato nel codice 2) è diverso da quello utilizzato nel codice 1). Trattasi infatti, di un classico esempio di overload: nel codice 1) è utilizzato il metodo println che prende come parametro una stringa:

  println(String)

mentre nel codice 2) è utilizzato il metodo println che prende come parametro un Object (e quindi un qualsiasi oggetto):

  println(Object)

e che stamperà una descrizione dell’oggetto passato utilizzando proprio il metodo toString().

- Collezioni eterogenee:



Una collezione eterogenea, è una collezione composta da oggetti diversi (ad esempio un array di Object che in realtà immagazzina oggetti diversi). Anche la possibilità di sfruttare collezioni eterogenee, è garantita dal polimorfismo per dati. Infatti, un array dichiarato di Object potrebbe contenere ogni tipo di oggetto, per esempio:

 Object arr[] = new Object[3];
 arr[0] = new Punto(); //arr[0], arr[1], arr[2]
 arr[1] = "Hello World!"; //sono reference ad Object
 arr[2] = new Date(); //che puntano ad oggetti
 //istanziati da sottoclassi


il che equivalente a:
 Object arr[]={ new Punto(),"Hello World!",new Date()} ;

Presentiamo di seguito un esempio allo scopo di intuire la potenza e l’utilità di questi concetti. Immaginiamo di voler realizzare un sistema che stabilisca le paghe dei dipendenti di un’azienda, considerando le seguenti classi:

class Dipendente
{
  String nome;
  int stipendio;
  int matricola;
  String dataDiNascita;
  String dataDiAssunzione;
}
class Programmatore extends Dipendente         
{
  String linguaggiConosciuti;
  int anniDiEsperienza;
}
class Dirigente extends Dipendente
{
  String orarioDiLavoro;
}
class AgenteDiVendita extends Dipendente
{
  String [] portafoglioClienti;
  int provvigioni;
}
. . .

Il nostro scopo è di realizzare una classe che stabilisca le paghe dei dipendenti. Potremmo ora utilizzare una collezione eterogenea di dipendenti, ed un parametro polimorfo per risolvere il problema in un modo molto semplice, veloce ed elegante. Infatti, potremmo dichiarare una collezione eterogenea di dipendenti:

 Dipendente [] arr = new Dipendente [180];
 arr[0]=new Dirigente();
 arr[1]=new Programmatore();
 arr[2]=new AgenteDiVendita();
 . . .

Esiste tra gli operatori di Java, un operatore binario costituito da lettere: instanceof. Tramite esso si può testare a che tipo di oggetto in realtà un reference punta:

public void pagaDipendente(Dipendente dip)
{
  if (dip instanceof programmatore)
  {
    dip.stipendio=2000000;
  }
  else if (dip instanceof Dirigente)
  {
    dip.stipendio=5000000;
  }
  else if (dip instanceof AgenteDiVendita)
  {
    dip.stipendio=1000000;
    . . .
  }
}

Ora, possiamo chiamare questo metodo all’interno di un ciclo di 180 iterazioni, passandogli tutti gli elementi della collezione eterogenea, e raggiungere così il nostro scopo:

. . .
for (int i=0; i<180; i++)
{
  pagaDipendente(arr[i]);
  . . .
}


Vai alla pagina:

Elenco delle pagine di "Il linguaggio Java: lez.7"

Introduzione e Unità didattica 6.1.1) - Pagina 1
Unità didattica 6.1.2) - Pagina 2



[Indietro]    [Su]      [Home]      [Commenti]      [V. Stampabile]

Commento di Anonimo (ip: 217.133.28.147), scritto il 12/12/2005 alle 17:24:46
ma ch' c'zz'

Commento di Anonimo (ip: 87.17.26.235), scritto il 07/08/2006 alle 19:12:33
sit stupidi
come possiamo imparare tutto al sud

Commento di Anonimo (ip: 87.17.26.235), scritto il 07/08/2006 alle 19:12:45
sit stupidi
come possiamo imparare tutto al sud

Commento di Anonimo (ip: 62.94.148.107), scritto il 13/07/2007 alle 11:47:55
il ''Polimorfismo per dati''...non è assolutamente chiaro.

Commento di Anonimo (ip: 83.184.32.218), scritto il 14/11/2007 alle 16:59:06
è fatto abbastanza bene, però concordo con l''anonimo che il polimorfismo per dati non è molto chiaro

Commento di Anonimo (ip: 87.11.225.253), scritto il 03/12/2007 alle 17:54:30
l polimorfismo per dati, permette essenzialmente di poter assegnare un reference di una superclasse ad un’istanza di una sottoclasse.???

Cosa sta a indicare???
Bah...! Semmai il polimorfismo x dati...
Assegna ad una Variabile Oggetto (di tipo Persona) di una Sper classe,
il riferimento a un Oggetto(di tipo Studente) di una Sotto classe.
Quindi, invocando il metodo parla() sull''istanza di Tipo Persona, referenziata sullo Studente, viene chiamato in gioco il binding dinamico..
Ossia il compilatore in run time decide L''oggetto che forma deve assumere, in funzione del reference.
In questo caso Studente!

Commento di Anonimo (ip: 87.11.225.253), scritto il 03/12/2007 alle 17:59:26
Persona pippo = new Studente();
pippo.parla();
// chiaramente il metodo della classe derivata sarà di tipo void
// o potete lavorare con il Costruttore in diversi modi..

Ciao saluti. :)

Commento di Anonimo (ip: 84.221.18.249), scritto il 21/04/2008 alle 17:44:30
comq tutto ciò che c''è scritto è un copia identica de Object Orinted && Java5 Claudio De Sio Cesari

Commento di Anonimo (ip: 88.35.188.250), scritto il 14/06/2008 alle 20:32:40
se non ho sbagliato a capire il polimorfismo per dati dovrebbe corrispondere al caso in cui si dichiara una collection...cm un set o una map...in qst casi infatti nn si può istanziare un oggetto di tipo set o map e quindi si istanzia un oggetto di una classe derivata...
ad esempio fare Map<Integer,String> mappa = new Map<Integer,String>(); è errore poichè Map è una classe astratta...e quindi si fa...
Map<Integer,String> mappa = new TreeMap<Integer,String>(); ...uso la TreeMap sl a titolo di esempio...ciaociao

Commenta questa notizia:
Non hai ancora fatto il
Login, puoi inserire commenti solo come anonimo.
ATTENZIONE: il tuo IP verrà memorizzato e mostrato a fianco del commento; con la pressione del tasto invia commento si esprime il consenso alla pubblicazione di tale informazione personale.
A discrezione dello staff, i commenti ritenuti non adatti od offensivi potranno essere rimossi. Nel caso di utilizzo di espressioni volgari od offensive il comportamento verrà segnalato al provider interessato.
Se non ti sei ancora registrato, cosa aspetti? Registrati subito.

Da ora puoi discutere dei problemi informatici anche sul nostro FORUM

Testo del commento:


  News correlate
 Corso Java @ilsoftware.it
 Il linguaggio Java: lez.10/10
 Il linguaggio Java: lez.9
 Il linguaggio Java: lez.8
 Il linguaggio Java: lez.7
 Il linguaggio Java: lez.6
 Il linguaggio Java: lez.5
 Il linguaggio Java: lez.4
  Ultime dal Forum

thesis disable comments on some pages
??????? Diult Diult Diult
essay on should we keep pets at home
writing an essay for college admissions
ib business and management past papers 2014
Zolpidem 5 mg APO ZOL 5
depression era essay
obstacles i overcame to attend college essay
russian march revolution essay

Comunicazioni / Note Legali / Staff / Collabora / Pubblicità / Privacy / Contatti


Triboo Media s.r.l. (società socio unico) - Viale Sarca 336 - Edificio 16, 20126 Milano (MI) Cap. Soc. 1.250.000,00 euro i.v. - P.IVA, C.F. e CCIAA di Milano IT06933670967 - REA MI-1924178 tel. +39 02 64741470 - fax +39 02 64741494 Società sottoposta alla direzione e coordinamento di TRIBOO SPA - all rights reserved CAP. SOC. EURO 28.740.210 I.V. - P.IVA 02387250307 - COD. FISC. e numero iscrizione al registro delle imprese CCIAA MI : 02387250307 tel.+39 02 64741401 - fax + 39 02 64741491. Utenti Connessi: 255


Pagina creata in 0,16sec. Powered by JuiceADV S.r.l.

Stats v0.1 (0,000sec.)