Upcasting

di il
5 risposte

Upcasting

Buonsalve,
mi ritrovo con un comportamento del codice che non riesco a spiegarmi.

class Instrument{
	public void play()
	{
	System.out.println("Play Instrument");	
	}

	static void tune(Instrument i)//***
	{
	 i.play();
	}
}

public class Wind extends Instrument{
	//OVERRIDE metodo() ereditato
	public void play()
	{
	System.out.println("Play Wind");
	}

	//OVERLOAD metodo() statico ereditato
	static void tune(Wind i) //**
	{
	 i.play();
	}	
	
	public static void main(String[] args)
	{
		Instrument flute2= new Wind();// UPCASTING
		
		//**
		Instrument.tune(flute2); //stampa "Play Wind"
		
		//***
		Instrument flute3=new Instrument();
		Wind.tune(flute3);
		Instrument.tune(flute3);
		
	}
}	
Ho un metodo statico (della ClassePadre) e questo metodo viene overloadato nella classe Figlio.
Ora, la classe Figlio eredita il riferimento della classe padre ( nomedellaClasse) .

Domanda: perché con quel riferimento della classePadre io sono in grado di invocare non solo il metodo della classePadre ma anche la sua versione overloadata nella classeFiglio?

DUBBIO: visto che quella versione overloadata , fondamentalmente "non ci sta" nella definizione della classe del Padre, ma è una esclusiva del Figlio
perchè (**)la posso comunque invocare col riferimento alla classePadre?

mi è chiaro che a quello ereditato (***) posso accedere con entrambi i riferimenti, perché tanto
-se accedo con quello del Padre —> sto accedendo ad un metodo della sua classe
- se accedo con quello del Figlio—-> sto accedendo ad un metodo ereditato

Ma non riesco a capire , perché col riferimento del Padre, dovrei essere in grado di invocare un metodo che seppur statico NON sta definito nella sua classe

5 Risposte

  • Re: Upcasting

    pepp1995 ha scritto:


    Domanda: perché con quel riferimento della classePadre io sono in grado di invocare non solo il metodo della classePadre ma anche la sua versione overloadata nella classeFiglio?

    DUBBIO: visto che quella versione overloadata , fondamentalmente "non ci sta" nella definizione della classe del Padre, ma è una esclusiva del Figlio
    perchè (**)la posso comunque invocare col riferimento alla classePadre?
    Nulla di tutto questo è vero.

    Se invochi Instrument.tune( .... );

    A patto che l'argomento passato è-un Instrument, allora il metodo eseguito (l'UNICO possibile) è il static void tune(Instrument i) di Instrument.

    Se invece invochi Wind.tune( .... );

    entra in gioco il concetto di overloading. Ci sono 2 metodi tune in overload e quale dei due verrà invocato DIPENDE dall'argomento (il tipo "statico" della variabile). E per le regole del overloading, viene scelto sempre il metodo più "specifico".

    Se l'argomento è-un Wind, allora verrà scelto (dal COMPILATORE, non a runtime!) il tune di Wind.
    Se l'argomento è-un Instrument ma non Wind (o più sotto di Wind), allora verrà scelto il tune di Instrument.
  • Re: Upcasting

    Se invochi Instrument.tune( .... );

    A patto che l'argomento passato è-un Instrument, allora il metodo eseguito (l'UNICO possibile) è il static void tune(Instrument i) di Instrument.

    OK, ma allora perché quando lo eseguo facendo
    Instrument.tune(flute2);
    mi stampa "Play Wind" ?

    L'argomento passato è di Tipo Instrument , quindi mi aspetto sia eseguito il metodo tune() della Classe Madre .
    Questo metodo dovrebbe invocarmi il metodo: play() MA di quella superClasse e non della Classe Figlia .
    Dunque , mi aspetterei la stampa di "Play Instrument",cosa che non accade. Perché?
  • Re: Upcasting

    pepp1995 ha scritto:


    OK, ma allora perché quando lo eseguo facendo
    Instrument.tune(flute2);
    mi stampa "Play Wind" ?
    Perché quello è un altro discorso, riguarda l'overriding di play ... non il overloading (in Wind) di tune! Non mescolare le cose!

    Su Instrument c'è 1 solo metodo tune. Quindi Instrument.tune(flute2); non può che chiamare quello! Ma l'argomento è flute2, il tipo di questa variabile è Instrument ma l'oggetto realmente referenziato è un Wind.

    tune() invoca play() e il play eseguito è quello dell'oggetto realmente istanziato. Wind ridefinisce play per stampare "Play Wind" quindi questo è quello eseguito.

    Per chiarire:
    	static void tune(Instrument i)
    	{
    	 i.play();
    	}
    i.play() NON vuol dire che invoca il play() di Instrument perché i è di tipo Instrument. play() è un metodo di istanza, quindi soggetto ad override (se ereditabile, e lo è). Quindi conta l'oggetto REALMENTE referenziato da i.
  • Re: Upcasting

    play eseguito è quello dell'oggetto realmente istanziato
    Credo mi sia chiaro
    Il metodo è sempre quello della classe padre,ma poi a tempo di esecuzione , quando faccio i.play() io sto accedendo al metodo play() dell'oggetto puntato da i (che è un oggetto della classe Figlia) seppur il riferimento sia della classe Padre

    Grazie mille
    E scusami per l'ora
  • Re: Upcasting

    pepp1995 ha scritto:


    play eseguito è quello dell'oggetto realmente istanziato
    Credo mi sia chiaro
    Il metodo è sempre quello della classe padre,ma poi a tempo di esecuzione , quando faccio i.play() io sto accedendo al metodo play() dell'oggetto puntato da i (che è un oggetto della classe Figlia) seppur il riferimento sia della classe Padre
    Esatto. Il compilatore sceglie solo la "forma" del metodo. Ovvero sa di dover invocare un metodo che si chiama play, senza argomenti, che è già noto su Instrument. Ma poi la versione realmente eseguita a RUNTIME dipende dall'oggetto realmente istanziato.
    Questo vale in generale per i metodi "di istanza" (non static) soggetti ad override.
Devi accedere o registrarti per scrivere nel forum
5 risposte