Newsgroup: it.comp.java
Titolo: Domandina Ereditarietà!...

C'è una cosa che mi manda ai pazzi. E' breve, dateci un'occhiata per favore.
Ho una classe con questo metodo:
  class Velivolo {
  ...
  public void toString() {
  System.out.println("Sono un velivolo");
  ...
  }
e una sottoclasse estesa con lo stesso metodo riscritto:
  class Elicottero extends Velivolo{
  ...
  public void toString() {
  System.out.println("Sono un elicottero");
  ...
  }
se io faccio questa dichiarazione:
Velivolo v = new Elicottero();
v è a tutti gli effetti istanza di Velivolo, giusto?
ma perchè diavolo se io vado a fare:
v.toString();
mi pubblica "Sono un elicottero"?? Non dovrebbe scrivere "Sono un Velivolo"?
Quantomeno in presenza di metodi con stessi nomi il metodo nella superclasse
dovrebbe avere priorità rispetto a quello di una sottoclasse...no?
Grazie!
--
Roger

 Velivolo"? 
La "colpa" è del polimorfismo:
http://www.itportal.it/developer/java/polimorfismo_34/default.asp
Ciao
-- 
Marco

 v è a tutti gli effetti istanza di Velivolo, giusto?
[cut]
No, e' un'istanza di Elicottero indicata mediante un reference di tipo
Velivolo...ma e' pur sempre un Elicottero.
Lucio
-- 
Lucio Benfante
Java User Group Padova: 
http://www.jugpadova.it
Brainbench MVP for Java 1: 
http://www.brainbench.com
MyTranscript: 
http://www.brainbench.com/transcript.jsp?pid=167064

 La "colpa" è del polimorfismo:
[cut]
Va bene grazie anche alle dispense da te linkate, sappiamo che v è SIA
istanza di Velivolo SIA di Elicottero. Nell'indecisione però v applica il
metodo della sottoclasse, cioè comportandosi come un Elicottero, giusto?
Ma allora perchè se introduco una classe banale:
    public Iscrizione() {
     }
        public void iscrivi(Elicottero e) {
        System.out.println("Iscritto elicottero!");}
        public void iscrivi(Velivolo v) {
        System.out.println("Iscritto velivolo!");}
E la eseguo:
        Iscrizione iscrizione=new Iscrizione();
        iscrizione.iscrivi(v);  // v è sempre Velivolo v= new Elicottero();
Mi stampa "Iscritto velivolo!" e quindi questa volta si comporta come
Velivolo, cioè 'dando retta' alla superclasse???
E' questo che proprio mi fa uscire di testa :)
Grazie ancora.
--
Roger

 E' questo che proprio mi fa uscire di testa :)
Devo dire che hai ragione a uscire di testa, questo e' uno dei motivi
per cui java viene criticato come linguaggio...
In termini tecnici si dice che l'overriding viene risolto a run-time e
l'overloading a compile-time, tutto quello che un umano potrebbe
desiderare sapere lo trovi a partire da qui
http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#227768
Il tutto deriva dalla differenza fra quello che effettivamente succede
a run-time e quello che puo' dedurre a compile time il compilatore.
Quando scrivi un'istruzione del tipo:
Veivolo v = new Elicottero();
la variabile 'v' viene dichiarata di tipo 'Veivolo' e questo e' quello
di cui tiene conto il compilatore, ma a run-time viene creato un
oggetto di tipo 'Elicottero'. Il compilatore accetta l'istruzione di
assegnamento in quanto 'Elicottero' e' un sottotipo di 'Veivolo'.
Dopo l'assegnamento il compilatore si dimentica del fatto che in
realta' l'oggetto referenziato da 'v' e' di tipo 'Elicottero',
trattandolo come se fosse di tipo 'Veivolo' come precedentemente
dichiarato. Poi scrivendo:
Elicottero e = new Elicottero();
Hai due variabili 'v' ed 'e' che tu sai referenziare due oggetti di
tipo 'Elicottero', ma quando scrivi:
iscrizione.iscrivi(v);
il compilatore cerchera' nella classe 'Iscrizione' un metodo il cui
parametro formale e' di tipo compatibile con il tipo del parametro
attuale [*] che PER QUANTO NE SA IL COMPILATORE e' di tipo 'Veivolo',
di conseguenza viene chiamato il metodo 'iscrivi(Veivolo v)'
Tutt'altra storia si ha quando scrivi:
v.toString();
La classe scelta a compile time e' 'Veivolo', ma l'invocazione del
metodo e' virtuale, questo significa che la JVM (Java Virtual
Machine) a run-time verifica il tipo dell'oggetto referenziato da
'v', nel caso sia un sottotipo del tipo di 'v', nel nostro caso e' di
tipo 'Elicottero' sottotipo di 'Veivolo', controlla se il metodo
'toString()' e' stato ridefinito, se cosi' e' lo invoca, infatti si
ottiene "Sono un Elicottero"
Concludendo: nel primo caso, overloading, tutto viene risolto a
compile-time dal compilatore usando le informazioni che sono in suo
possesso ('v' e' stato dichiarato di tipo 'Veivolo'), nel secondo
caso, overriding, una parte viene giocata anche dalla JVM la quale
conosce lo stato attuale della computazione e la sfrutta ('v'
referenzia un oggetto di tipo 'Elicottero' che e' un sottotipo di
'Veivolo')
Spero di essere stato chiaro, sicuramente non sono stato precisissimo,
se vuoi ulteriormente approfondire segui il link che ti ho proposto
all'inizio.
Bye
[*] I parametri formali sono quelli dichiarati nel metodo, i parametri
attuali sono quelli utilizzati nella chiamata del metodo
-- 
{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}
SunGray aka Gabriele Lana
contact me @ 
gabrie...@fastwebnet.it
See you space cowboy ...

 l'overloading a compile-time,
[cut]
Grazie mille della risposta innanzitutto.
Allora ri-riassumendo, possiamo affermare che il nostro v così formato
Velivolo v=new Elicottero() è in realtà un 'ibrido': "ufficialmente" è un
Velivolo, "ufficiosamente" è un Elicottero?..
Quando v agisce 'in prima persona' cioè v.toString() la JVM invoca,
trovandolo, il metodo del sottotipo Elicottero (se non fosse stato
ridefinito chiaramente invocava il toString() del supertipo Velivolo). -
OVERRIDING
Quando invece è un'altra classe che agisce (Iscrizione) e v ha ruolo per
così dire passivo, Iscrizione si basa solo sui parametri formali o
"ufficiali" dichiarati in precedenza dal compilatore, quindi in quel caso
Velivolo. - OVERLOADING
Spero di aver capito bene, mi sembra però un bel bug nell'ormai linguaggio
per eccellenza Java!
Un ultimo chiarimento: lo stesso ragionamento è applicato nel caso delle
interfacce e delle sottoclassi che le implementano giusto?
Tnx
--
Roger

 delle interfacce e delle sottoclassi che le implementano giusto?
Esatto, le interfacce non sono altro che vincoli del tipo
"compilatore, assicurati che questa classe implementi i metodi
dichiarati in questa interfaccia" niente di piu', niente di meno,
quindi non interferisce nei meccanismi di cui sopra
[*] In realta' fino alla 1.5 java non era strong type safe neanche un
pochino :-( ma questa e' un'altra storia


 delle interfacce e delle sottoclassi che le implementano giusto?
Nel caso delle interfacce non c'e' un implementazione, quindi il problema
non si pone.


 Velivolo, cioè 'dando retta' alla superclasse???
Stai confondendo due cose assolutamente diverse: il binding dinamico,
relativo all'esempio nel tuo post precedente, ed il meccanismo di
risoluzione dell'overloading, relativo invece a questo tuo ultimo esempio.
Siccome sono due concetti cardine della programmazione OO, ti consiglio di
non affrontarli a cuor leggero. Due buoni libri sull'argomento sono:
"Thinking in Java" e  "Core Java2".
In bocca al lupo,
Sergio B.
-- 
Sergio Bossa
Author and Developer of:
- Montag, Web Services System for XML Database Interaction:
 
http://montag.sourceforge.net
- QuickNote:
 
http://quicknote.sourceforge.net

 polimorfismo in Java, si tratta solo di comprenderlo.
[CUT]
Esatto.
Concordo!


 quindi non interferisce nei meccanismi di cui sopra
Ok!
Grazie duemila, ritieniti prenotato per un prossimo chiarimento in futuro!
;)
Ciao
--
Roger

 polimorfismo in Java, si tratta solo di comprenderlo.
Concordo, "bug" nel senso che ciò che sembra intuitivo a prima vista in
realtà non lo è, e in genere solo se si va a cercare di spezzare in due il
capello (effettivamente il caso visto è un po' un cavillo) ci si può
imbattere in queste problematiche apparentemente "nascoste".
Penso che un comune programmatore che non abbia approfondito Java ma che
scrive attraverso esso semplici programmi per siti, applet etc.
difficilmente possa incappare in questi problemi, ma se capitasse potrebbe
entrare in crisi :)
--
Roger