Newsgroup: it.comp.java
Titolo: Ereditarietà (un po' lungo)

La questione è banale (forse), ma non mi capacito di una cosa: allora,
supponendo di avere una superclasse A ed una classe derivata B, secondo 
il principio di ereditarietà, così come lo interpreto io, ogni oggetto 
di classe B è anche un oggetto di classe A mentre il viceversa non è 
vero. La classe B "specializza" la classe A e, correggetemi se sbaglio, 
le istanze di B rappresentano un sottoinsieme proprio dell'insieme 
dell'istanze di A; allora, secondo questa interpretazione io dovrei 
poter eseguire un'istruzione di questo tipo:
B b = new A();
invece questa istruzione è segnalata come errore dal compilatore, mentre 
risulta leggittima l'istruzione:
A a = new B();
tale comportamento è giustificato, secondo le informazioni raccolte un 
po' in giro su Internet e anche su alcuni testi da me consultati, dal 
fatto che, nel secondo caso, essendo un oggetto di classe A più 
"generale" di uno di classe B allora è accettabile che venga istanziato 
indifferentemente usando sia il proprio costruttore sia quello della 
sottoclasse, mentre nel primo caso ovviamente no.
Ritengo entrambi i ragionamenti corretti, ma in qualche modo 
contradittori tra loro. Dove sbaglio?
La mia perplessità è rafforzata dal fatto che, poi, se forzo un oggetto 
di classe A a diventare di classe B ottengo un errore a run-time.
Quindi se dichiaro un oggetto di classe A e lo istanzio di classe B va 
tutto bene, mentre se ho un oggetto di classe A e lo voglio forzare a 
diventare di classe B non va più bene.
Qualcuno saprebbe, cortesemente, rispondermi e chiarirmi le idee?
Grazie a tutti.
Luciano.

 classe B "specializza" la classe A e, correggetemi se sbaglio, [...]
Secondo me, sarebbe meglio se considerassi delle classi con nomi concreti.
A = Frutto (superclasse)
B = Mela (classe derivata da Frutto)
E' ovvio che ogni Mela è un Frutto.
Ma ogni Frutto NON è una Mela.
Frutto fruit = new Mela();
è corretto perchè fruit è genericamente un Frutto, che viene poi 
specializzato ad essere una Mela.
E dal momento che ogni Mela è un Frutto, non ci saranno problemi.
Mela fruit = new Frutto();
è sbagliato perchè fruit è una Mela e quindi può possedere caratteristiche 
(metodi e proprietà) non compatibili con il Frutto in generale.
Prova a fare qualche esperimento inserendo un metodo toString() che stampa 
il tipo di oggetto.
Frutto stamperà "un Frutto". Mela stamperà "una Mela".
Dopodichè richiama tale metodo all'interno del costruttore.
Infine prova ad istanziare alcuni oggetti di tipi diversi (magari crea altri 
frutti, pere, banane, ...) e vedi che succede.
Ciao
Marco 

 B b = new A();
Chiaramente non lo puoi fare. Prendi ad esempio questo caso:
public class A
{
public void foo() {}
}
public class B extends A
{
public void foo2() {}
}
Secondo la tua ipotesi, avresti un riferimento di tipo B che punta ad
una istanza concreta di A. Ciò ti consente di avere accesso al metodo
foo2() inconsistente nell'oggetto concreto.

 foo2() inconsistente nell'oggetto concreto.
ma poichè in Java vale il late binding, di fatto l'oggetto che istanzio 
è di classe A e non B.
Infine ripropongo l'ultima parte della questione:
E' sempre possibile forzare in upcasting un oggetto di classe B a 
diventare di classe A:
B b = new B();
A a = (A)b;
e' una sequenza di istruzioni lecita, di fatto ho un oggetto dichiarato 
di classe A che concretamente riferisce un oggetto di classe B.

 il che vuol dire che B è sottoinsieme proprio di A.
Non parlare di "oggetti", che non c'entrano in questo contesto. Le
classi hanno dei membri, che si suddividono in metodi e attributi
(field). Questi in base alla loro visibilità vengono ereditati.

> metodo foo2() inconsistente nell'oggetto concreto.
M> ma poichè in Java vale il late binding, di fatto l'oggetto che
M> istanzio è di classe A e non B.  
Prima del late binding, molto  prima, in Java vale la puntigliosità in
fase di  compilazione. Ora il  compilatore quando si trova  davanti ad
una  assengazione A  = new  B() spara  fuori il  suo bel  messaggio di
errore  in quanto  l'operazione è  prona  a generare  in futuro  delle
eccezioni di metodo non trovato. 
E'  vero che  una si  può capire  in certi  casi se  la cosa  si mani-
festerebbe o no a runtime, ma  non lo può determinare in tutti i casi,
quindi la cosa "Java Style" da fare è non permetterla.
-- 
 /\            ___
/___/\__|_|\_|__|___Gian Uberto Lauri_____________________
  //--\ | | \|  |   Integralista GNUslamico  
\/		    e allevatore di bug da competizione