Newsgroup: it.comp.java
Titolo: ereditarietà e ridefinizione di metodi

Supponiamo che in una classe a sia presente un metodo a1 che, al suo 
interno, richiama un metodo a2.
Supponiamo che esista una classe b che estende la classe a, che eredita il 
suo metodo a1 (protected o pubblic), ma ridefinisce il metodo a2.
Quando viene eseguito il metodo a1 (quello ereditato dalla superclasse, non 
ridefinito in b) java utilizza il metodo a2 della superclasse, o quello che 
è stato ridefinito nella classe che ne ha ereditato il metodo?
Cambia qualcosa se a1 è il costruttore? 


Da qualche prova che ho fatto, sembra che se a1 è dichiarato private venga 
usato il metodo a1 della superclasse, mentre se è dichiarato protected 
quello ridefinito nella classe figlia. Giusto? 

 quello ridefinito nella classe figlia. Giusto?
Mi pare strano, dovrebbe usare sempre quello ridefinito
cya N
 
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

 Mi pare strano, dovrebbe usare sempre quello ridefinito
Eppure giuro che è così (ho riprovato per sicurezza):
Caso 1) Il costruttore della classe a richiama il metodo privato b; la 
classe a1 che estende la classe a ridefinisce il metodo b, mentre il suo 
costruttore è costituito solo dall'istruzione super().
Effetto: quando l'istruzione super() viene eseguita probabilente java va a 
guardare il costruttore della classe a, lì trova richiamato un metodo 
privato (quindi non ereditabile), ed esegue quelo, fregandosene 
dell'esistenza di un metodo con lo stesso nome nella classe madre.
Caso 2) Il costruttore della classe a richiama il metodo protetto b; la 
classe a1 che estende la classe a ridefinisce il metodo b, mentre il suo 
costruttore è costituito solo dall'istruzione super().
Effetto: quando l'istruzione super() viene eseguita probabilente java va a 
guardare il costruttore della classe a, ma stavolta trova richiamato un 
metodo protected (quindi ereditabile), e di conseguenza cerca se è stato 
ridefinito. In caso affermativo, stavolta, esegue il metodo della classe 
figlia. 

 Eppure giuro che č cosě (ho riprovato per sicurezza):
In effetti non e' corretto
in teoria un buon compilatore dovrebbe addirittura darti errore
di fatto non ha senso fare un ovverride di un private
ciao Nicola


 
Invece funziona proprio così.
In Java i metodi private e static subiscono un binding statico, significa
che il codice è collegato al momento della compilazione. Vengono eseguiti
i metodi definiti al momento della compilazione*.
I metodi protected e public subiscono un binding dinamico, il metodo
giusto da eseguire viene trovato a runtime, se Marco vuole applicare il
template method pattern (che è quello che sta facendo) il metodo a2,
chiamato da a1, deve essere almeno protected.
Chi chiama a1 su un istanza di qualsiasi classe figlia, eseguirà l'a2
della classe figlia instanziata.
*) Prova per esempio a creare una classe che espone una variabile statica
per esempio:
static int a = 2;
poi compila una classe che utilizza questa variabile.
Ora cambia il valore ad a nel sorgente e ricompila solo la prima classe.
Se esegui il codice della seconda classe vedrai che mantiene il valore di
a pari a 2, anche se nella nuova classe ha un valore diverso. Questo
perché la variabile è stata salvata nella classe che la utilizza
(binding statico)
-- 
Pietro	- 
http://www.pietroweb.tk
Linux Registered User #304991
Powered by MDK Linux Kernel 2.6.10

 di fatto non ha senso fare un ovverride di un private
Eppure non mi sembra del tutto insensato; tieni conto che i metodi di cui 
parlo sono richiamati tutti dal costruttore, e che super indica a tutti gli 
effetti il costruttore della classe madre... non č del tutto insensato che 
utilizzi i metodi privati della propria classe, se privati e quindi non 
ridefiniti.
Non ho ancora fatto nessuna prova con un metodo ridefinito, ma richiamato da 
un altro metodo, e non dal costruttore...
N.B. TUTTE le versioni java a mia disposizione, ovvero 1.2.1, 1.3.1_14, 
1.4.2_07 e 1.5.0_02 si comportano allo stesso modo. 

 (binding statico)
Ottimo ora abbiamo una spiegazione tecnica.
C'e' da dire pero' che da un punto di vista della programmzaione non so se
ha senso fare un override di un private e potrebbe anche fermarti il
compilatore
io comuqnue non ho problemi perche' non uso mai private.
O public o protected
iperrarissimamente metto un private final
ciao Nicola


 di fatto non ha senso fare un ovverride di un private
Ma no, e' giusto cosi'!
Se la classe B estende A, il metodo privato di A e' come "se non 
esistesse" per lei. Viceversa, il metodo pubblico o protetto viene 
ereditato, per cui si puo' correttamente parlare di metodo ridefinito e 
allora vale il binding dinamico.
Il compilatore non c'entra.
Saluti
CarMas

 ha senso fare un override di un private
Non si puo' parlare di override, perche' sono metodi visibili ed 
accessibili solo alle proprie classi base.
E' solo una coincidenza di nomi :D
Saluti
CarMas

 allora vale il binding dinamico.
Aggiungo che, poichè l'istruzione super() deve essere la prima invocata dal 
costruttore della classe figlia, non esisterebbe possibilità di ridefinirlo 
(ma solo di aggiungere ulteriori istruzioni) se non richiamando metodi 
protected o public nel costruttore della superclasse, e ridefinendo tali 
metodi nella classe figlia. Così richiamando il costruttore della classe 
madre con super si possono eseguire, di fatto, compiti diversi. 

 quello ridefinito nella classe figlia. Giusto? 
Si. Generalizzando, non è possibile per una classe discendente 
"nascondere" (hide) i metodi privati della classe padre.

 di fatto non ha senso fare un ovverride di un private
Infatti non fa l'ovverride. Sbaglia il programmatore se pensa di farlo.

 metodi nella classe figlia.
richiamare metodi non privati o final dall'interno di un costruttore però
è un errore di programmazione ben noto e può portare evidentemente a stati
inconsistenti negli oggetti. Va evitato sempre.
richiamare metodi non privati o final da un metodo (dunque non un
costruttore) che sia "overridable" è invece meno scorretto ma comunque
problematico: il problema potenziale che si genera è noto in letteratura
come classe base fragile.
Un (auto)riferimento, tanto per risparmiare banda,
http://www.mokabyte.it/2004/06/fbc.htm
ciao, hth
uL
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 iperrarissimamente metto un private final
Quando ci mandi una copia di questi standard di codifica? :)


Dò anch'io il mio contributo. Me ne accorsi (di questa cosa) un po' di
tempo fa e poi ne trova conferma su Thinking in Java che così riporta:
(...)a private method is automatically final, and is also hidden from
the derived class. So Derived's f( ) in this case is a brand new
method; it's not even overloaded, since the base-class version of f(
) isn't visible in Derived.
The result of this is that only non-private methods may be overridden,
but you should watch out for the appearance of overriding private
methods, which generates no compiler warnings, but doesn't do what
you might expect. To be clear, you should use a different name from a
private base-class method in your derived class

 inconsistenti negli oggetti. Va evitato sempre.
il costruttore, che e' un metodo, non privato, e' quasi sempre chiamato nel costruttore
delle classi derivate..dunque con quanto affermi, commettiamo sempre questo
sacrilegio :)

 Quando ci mandi una copia di questi standard di codifica? :)
Pensa che un noto teorema dice qualsiasi linguaggio attuale e' traducibile
in uno di Von Neumann
un altro dice che puoi costruire un calcolatore elettronico con solo
l'elemento NAND
Ognuno ha il suo stile di programmazione
Quello che conta e' che alla fine i programmi siano
corretti
robusti
facilmente manutenibili
Se tu utilizzi ogni caratteristica del linguaggio, buon per te, spero che
siano poi facilmente manutenibili, sempreche' sono corretti, visto che
usando cose che sono utili + per la settimana enigmistica che per fare buoni
progetti non vorrei che poi si caschi sulla buccia di banana.
Ti rispondo cosi visto il tono della tua risposta e visto anche che dopo il
comunque utile dibattito sulle httpsession ed ejb Stateful in cluster, mi
sto documentando e hai detto cose non del tutto giuste.
Gli appserver migliori gestiscono chiaramente gli ejbstateful in cluster se
no sarebbe inutile tutto il j2ee
e anche a livello di httpsession ci sono vari modi per gestire il balancing.
Nonostante l'argomento attuale e' comunque curioso, se mi vai a nominare un
metodo di una classe estesa col nome omonimo di un metodo private della
madre e' evidente che crei una non lieve ambiguita' e' difficolta' di
lettura Io sconsiglierei a tutti di farlo.
Buon lavoro e divertiti a persistentizzare gli ejb stateful


 stati inconsistenti negli oggetti. Va evitato sempre.
Questo non mi è del tutto chiaro... Perché mai non si potrebbe fare?
Cioè se per esempio ho una classe astratta tu dici che è sbagliato
questo:
public abstract class A {
	protected A() {
		init();
	}
	protected abstract void init();
	// Altri metodi
}
Pensa che esiste un template per questo...


 ciao Nicola
Scusa per la risposta.
Mi sono letto il tuo articolo e sei molto in gamba.
Scrivo in fretta durante il lavoro e uso il NG come una via di mezzo fra
chat e forum, come credo sia il suo scopo. E spesso "ci si mena un po'". E'
+ divertente :-)
Per quanto riguarda il problema della classe debole direi che il tuo
articolo chiarisce tutto completamente.
Per quanto riguarda il vecchio problema delle Session e degli Stateful, sto
cercando nei ritagli di tempo e mi pare che WebSphere e WebLogic abbiano dei
meccanismi di indirizzamento delle richieste senpre verso la stessa istanza
del cluster.
Non so Jboss.
Se cosi' non fosse bisogna ammettere che il discorso del j2ee che fa dl
balancing il suo cavallo di battaglia, perderebbe molta incisivita'.
Andro' avanti negli studi, sarebbe bello trovare una tabella con le
modalita' di trattamento delle session dei vari AppServer in cluster.
ciao e scusa ancora.


AtmO ha scritto:


no, perchè il problema deriva dalla natura polimorfa dei metodi, e i
costruttori non sono polimorfi. Il problema della fragilità deriva
esclusivamente dal polimorfismo
Comunque, a proposito del sacrilegio :) 
1) il costruttore non è un metodo: per esempio non ha tipo di ritorno, non
può essere statico, non può essere sincronizzato, non si eredita e non se
ne può fare l'override, non può essere invocato direttamente, deve
chiamarsi come la classe che lo ospita, e tante altre cosette 
2) viene sempre chiamato dalle classi derivate e non "quasi sempre",
talvolta in modo implicito talvolta in modo esplicito
ciao


 Pensa che esiste un template per questo...
pensa che JBuilder uno (e due, mi sembra) produceva codice di questo tipo
ad ogni piè sospinto. Poi mi sembra che abbiano reso il famigerato
jbInit() final o privato nelle versioni "moderne".
Comunque il template di cui sopra ha l'init() astratto, per cui è ok.


 lettura Io sconsiglierei a tutti di farlo.
certo, č infatti una bad practice


 Inviato via 
http://arianna.libero.it/usenet/


 failover, non il load balancing
Gia' il balancing e' un bel traguardo.
Prendiamo tutto il range delle applicazioni web con un carrello di qualsiasi
tipo.
Per queste applicazioni il balancing e' una gran conquista, perche permette
di reggere grossi carichi di accessi, il failover puo' dare un errore
all'utente, buttarlo fuori e dirgli che c'e stato un inconveniente e
ricominciare.
Nel caso il failover fosse critico, si puo' procedere alle tecniche di
rendere persistenti le session di cui parlavi tu
ciao Nicola


 talvolta in modo implicito talvolta in modo esplicito
giusto.


 
Capisco che vuoi dire, infatti nell'esempio da me fatto la classe era
astratta. Di solito lo uso per consentire l'inizializzazione di qualche
oggetto a seconda del tipo di classe derivata.
Non avrebbe senso inizializzare oggetti e consentire alle sottoclassi di
sovrascrivere il metodo...
Comunque resta il fatto che l'errore lo commette chi sovrascrive il metodo
senza sapere perché...


 superclasse...ma sennò l'override lo fai..
E quindi, come lo fai?

 senza sapere perché...
No, in questo caso è un errore di progettazione e lo commette chi ha 
scritto la classe astratta. Chi scrive la classe derivata e in 
particolare il metodo init() va in contro a dei problemi anche se sa a 
cosa serve quel metodo.

 E quindi, come lo fai?
public class Object {
public Object(E a) { }
}
public class Oggetto extends Object {
public Oggetto(E a) {
super(a);


 abbia il controllo.
Ovviamente nel mio esempio assumevo che chi estende A e deve implementare
B sa cosa fa.
Per esempio ho una classe astratta Edge, e due derivate Edge2D e Edge3D.
Lo stesso per la classe Arrow.
un Edge ha un istanza di Arrow a seconda del tipo (2D o 3D).
La variabile è definita in Edge.
rendendo il metodo init astratto posso, nelle classi Edge2D e Edge3D
creare il tipo di Arrow (2D o 3D) adatto, lasciando la variabile nella
classe Edge (di tipo Arrow)
Ci sono altri metodi per fare ciò?


 Ci sono altri metodi per fare ciò?
Così a senso, darei un'occhiata al builder pattern su come ottenere un 
istanza concreta di Edge. O eventualmente qualche altro creational 
pattern. Senza inventarmi soluzioni di fantasia e error prone, i design 
pattern sono lì apposta.

 }
Questo non è override.
Comunque non insisterei più di tanto, qualsiasi testo esplicita nella 
definizione dei costruttori che non possono essere ereditati ne fatto 
l'override (adesso ho sottomano il testo-guida per la certificazione).



Li ho guardati i design, ma la soluzione che ho trovato mi sembra quella
più pulita. Tra l'altro né il builder, né il creational mi convincevano
in questo problema..
Comunque se conosci una soluzione migliore io sono aperto ad ogni
evenienza...
Dico solo che avere un metodo init() che inizializza alcune variabili,
oppure lasciarle inizializzare a qualcun altro con qualche pattern come
dici tu, può sempre lasciare le variabili non inizializzate e avere uno
stato inconsistente..
Qual è la tua idea?


Da Java Fondamenti di Programmazione, Deitel & Deitel, Apogeo:
"Un costruttore è un metodo che ha lo stesso nomde della classe [...]"
Hanno sbagliato loro? Loro dicono che è un metodo.


 Hanno sbagliato loro? Loro dicono che è un metodo.
Si stava dicendo che i costruttori non possono essere ereditati ne fatto 
l'override.

 Qual è la tua idea?
Non conosco il problema nel dettaglio per cui ovviamente un idea non
posso dartela. Però resta valido il principio di non inventare l'acqua
calda; credimi, è molto improbabile essere di fronte ad una problematica
talmente originale da dover ricorrere alla fantasia.
Le stesse API di java implementano tutte modelli consolidati. Per
esempio (uno dei tanti), se hai bisogno di un costrutto per il building
di oggetti complessi, potresti ispirarti alla costruzione dei DOM
(javax.xml.parsers.DocumentBuilder e DocumentBuilderFactory).

 Hanno sbagliato loro? Loro dicono che è un metodo.
è probabilmente una semplice spiegazione per far capire meglio. Leggi i
testi di riferimento, le specifiche sono scaricabili online.
uL
P.S.
E' bello discutere di tutto, ma non è che tutto sia opinabile, eh? Poi qui
su it.comp.java sono tutti bravi ragazzi, su altri ng ti risponderebbero
molto semplicemente "RTFM: i costruttori non sono metodi" ;)


 Ci sono altri metodi per fare ciň?
Il tuo approccio č un'applicazione del Factory Method: concordo con Vincent
che utilizzarlo nel costruttore ha degli svantaggi, ma come messo in
evidenza da Ugo, č comunque "safe", finchč l'init() sovrascritto č
astratto.
Potresti sbrogliare la situazione utilizzando l'inizializzazione "lazy",
pigra, ossia inizializzando gli oggetti sempre all'interno di init(), ma
facendo sě che questi venga chiamato non dal costruttore ma dal metodo che
accede la prima volta agli oggetti in questione; ad esempio: getArrow().
Non č detto tuttavia che nella tua applicazione una cosa del genere sia
fattibile.
Un saluto,
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



Si, infatti ora ti credo..
però guardando quel libro c'è scritto questo e per questo ho detto che i
costruttori sono metodi.
Un'altra cosa.. Sicuramente hai più esperienza di me..
Dici che il blocco static { } è diverso da un costruttore statico, ma per
esempio in C#, dove il costruttore statico esiste ( e.g.: static Object()
{ } ) fa esattamente le stesse cose che fa lo static {} in Java.
Qual è la differenza allora?
Perché lo static {} non si può chiamare costruttore statico?
