Domanda semplice teorica sull'ereditarietà

di il
1 risposte

Domanda semplice teorica sull'ereditarietà

Ciao a tutti

Quando io in una sottoclasse s decido di sovrascrivere un metodo della sua superclasse S (ossia decido di riutilizzare quanto già fa un metodo di S, con qualche piccola variante funzionale a quanto devo fare in s), ridefinisco il metodo con la stessa intestazione e nel corpo del metodo, una volta "aggiunto" la variante che volevo fare, richiamo il metodo di S attraverso la sintassi:

super.nomeMetodo(..).

Fin qua tutto chiaro giusto?

Ecco la mia domanda è la seguente: se il metodo della superclasse S ha un valore di ritorno, e io nella sottoclasse voglio modificare il metodo con un'operazione che non va a influire sul valore di ritorno (ad esempio inserisco un contatore: ogni volta che viene eseguito quel metodo viene incrementato di uno), comunque nel corpo del metodo devo inserire la parola "return", anche se il return lo dovrebbe già fare il metodo della superclasse? Altrimenti il compilatore mi da errore di mancanza di valore di ritorno".

Provo a spiegarmi meglio con un esempio:
public SottoClasse{
     public static int metodoDaSovrascrivere(...){
         variante
         super.metodoDellaSuperClasse(..)
     }
Questo codice risulta errato perché manca il valore di ritorno. JAVA richiede sempre che io lo metta anche se il ritorno dovrebbe essere già effettuato nella superclasse?

E' un concetto un po' macchinoso spero di essermi spiegato.

1 Risposte

  • Re: Domanda semplice teorica sull'ereditarietà

    Ciao! La risposta breve è: si, in ogni metodo che specifica un valore di ritorno devi SEMPRE mettere un return, anche se il metodo è overriden.

    Il motivo è che, di fatto, si tratta di due metodi diversi, un po' come se avessi il seguente esempio:
    
    public int moltiplica(int a, int b) {
    	int result = 0;
    	for (int i=0; i<b; i++) {
    		result = somma(result,a);
    	}
    	// Cosa restituisco?
    }
    
    Cioè è vero che il metodo "somma" restituisce un valore, ma questo non dice nulla su ciò che dovrà restituire il metodo "moltiplica", per il quale dovrai esplicitamente mettere un valore di return.
    Allo stesso modo, se non metti il return, la classe figlia non sa cosa restituire al chiamante, anche se la classe madre restituisce qualcosa.

    Inoltre vorrei farti notare l'ordine in cui hai ridefinito il metodo:
    
    public static int metodoDaSovrascrivere(...){
             variante
             super.metodoDellaSuperClasse(..)
         }
    
    Ovvero richiami il metodo della superclasse DOPO aver fatto delle modifiche. Questa cosa di per sé non è sbagliata, ma guarda le seguenti classi:
    
    public class Madre {
    	protected Counter c;
    
    	public int metodo() {
    		c = new Counter();
    		return c.getCount();
    	}
    }
    
    
    public class Figlia extends Madre {
    
    	@Override
    	public int metodo() {
    		c.increment(); // NullPointerException
    		return super.metodo();
    	}
    }
    
    Se provi ad eseguire questo codice in un main (supponendo di aver definito da qualche altra parte la classe Counter) otterrai un NullPointerException. Infatti nel metodo della classe Figlia tenti di accedere ad una variabile che non è ancora stata inizializzata, in quanto l'inizializzazione è "a carico" del metodo della classe Madre, che però richiami DOPO aver tentato di modificare la variabile. Di conseguenza in generale l'ordine in cui esegui il codice Madre/Figlia è importante e fa la differenza.
    Nota che in questo caso specifico te ne accorgi facilmente a runtime perché viene sollevata un'eccezione, ma potresti avere cose più subdole, tipo:
    
    public class Madre {
    	protected Counter c;
    
    	public Madre() {
    		c = new Counter();
    	}
    
    	public int metodo() {
    		c.setCount(0);
    		return c.getCount();
    	}
    }
    
    public class Figlia extends Madre {
    
    	public Figlia() {
    		super();
    	}
    
    	@Override
    	public int metodo() {
    		c.setCount(10);
    		return super.metodo();
    	}
    }
    
    public class Main {
    	public static void main(String[] args) {
    		Figlia f = new Figlia();
    		System.out.println(f.metodo());
    	}
    }
    
    In questo caso non viene lanciata nessuna eccezione, ma la modifica "c.setCount(10)" viene sovrascritta dal metodo della classe Madre!
Devi accedere o registrarti per scrivere nel forum
1 risposte