2012-10-09 11 views
6

Sto cercando di ottenere il blocco dell'ereditarietà in Java e ho imparato che quando si esegue l'override dei metodi (e nascondendo i campi) nelle sottoclassi, è ancora possibile accedervi da la super classe usando la parola chiave 'super'.Uso della parola chiave 'super' quando si accede a metodi di superclasse non sovrascritti

Quello che voglio sapere è se la parola chiave 'super' dovrebbe essere utilizzata per metodi non sovrascritti?

C'è qualche differenza (per metodi non sovrascritti/campi non nascosti)?

Ho messo insieme un esempio qui sotto.

public class Vehicle { 
    private int tyreCost; 

    public Vehicle(int tyreCost) { 
     this.tyreCost = tyreCost; 
    } 

    public int getTyreCost() { 
     return tyreCost; 
    }   
} 

e

public class Car extends Vehicle { 
    private int wheelCount; 

    public Vehicle(int tyreCost, int wheelCount) { 
     super(tyreCost); 
     this.wheelCount = wheelCount; 
    } 

    public int getTotalTyreReplacementCost() { 
     return getTyreCost() * wheelCount; 
    } 
} 

In particolare, dato che getTyreCost() non è stato ignorato, dovrebbe getTotalTyreReplacementCost() uso getTyreCost(), o super.getTyreCost()?

Mi chiedo se Super debba essere utilizzato in tutti i casi in cui si accede a campi o metodi della superclasse (per mostrare nel codice che si sta accedendo alla superclasse), o solo in quelli sovrascritti/nascosti (quindi spicca).

risposta

10

Non utilizzare la parola chiave super per fare riferimento ad altri metodi che non sono sovrascritti. Rende confuso per altri sviluppatori che cercano di estendere le tue classi.

Diamo un'occhiata ad un codice che fa utilizza la parola chiave super in questo modo. Qui abbiamo 2 classi: Dog e CleverDog:

/* file Dog.java */ 
public static class Dog extends Animal { 

    private String name; 

    public Dog(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

} 

/* file CleverDog.java */ 
public class CleverDog extends Dog { 

    public CleverDog(String name) { 
     super(name); 
    } 

    public void rollover() { 
     System.out.println(super.getName()+" rolls over!"); 
    } 

    public void speak() { 
     System.out.println(super.getName() + " speaks!"); 
    } 

} 

Ora, immaginate sei un nuovo sviluppatore del progetto, ed è necessario un po 'di comportamento specifico per un cane intelligente che è in tv: che il cane ha a che fare tutto i suoi trucchi, ma dovrebbe andare dal suo nome fittizio TV. Per fare questo, è l'override del metodo getName(...) ...

/* file DogOnTv.java */ 
public class DogOnTv extends CleverDog { 

    String fictionalName; 

    public DogOnTv(String realName, String fictionalName) { 
     super(realName); 
     fictionalName = fictionalName; 
    } 

    public String getName() { 
     return fictionalName; 
    } 

} 

... e cadere in una trappola tesa dallo sviluppatore originale e il loro uso insolito della parola chiave super!

Il codice sopra non funziona, perché nell'implementazione originale CleverDog, getName() viene richiamato utilizzando la parola chiave super. Ciò significa che invoca sempre Dog.getName() - irrilevante di qualsiasi override. Di conseguenza, quando si utilizza il nuovo tipo DogOnTv ...

System.out.println("Showcasing the Clever Dog!"); 
    CleverDog showDog = new CleverDog("TugBoat"); 
    showDog.rollover(); 
    showDog.speak(); 

    System.out.println("And now the Dog on TV!"); 
    DogOnTv dogOnTv = new DogOnTv("Pal", "Lassie"); 
    dogOnTv.rollover(); 

... si ottiene l'uscita sbagliata:

Showcasing the Clever Dog! 
Tugboat rolls over! 
Tugboat speaks! 

And now the Dog on TV! 
Pal rolls over! 
Pal speaks! 

Questo non è il solito comportamento previsto quando si modifica un metodo, in modo da dovrebbe evitare di creare questo tipo di confusione usando la parola chiave super a cui non appartiene.

Se, tuttavia, questo è in realtà il comportamento desiderato, utilizzare la parola chiave final invece - per indicare chiaramente che il metodo non può essere ignorato:

/* file CleverDog.java */ 
public class CleverDog extends Dog { 

    public CleverDog(String name) { 
     super(name); 
    } 

    public final String getName() { // final so it can't be overridden 
     return super.getName(); 
    } 

    public void rollover() { 
     System.out.println(this.getName()+" rolls over!"); // no `super` keyword 
    } 

    public void speak() { 
     System.out.println(this.getName() + " speaks!"); // no `super` keyword 
    } 

} 
-1

Si consiglia che ulteriori modifiche alla classe ereditata non richiederanno l'aggiunta del super-qualificatore e inoltre eviteranno errori se persi.

1

Se si utilizza super, si sta dicendo esplicitamente di utilizzare il metodo di super classe (indipendentemente dalla sottoclasse che ha o meno il metodo sovrascritto), altrimenti jvm prima controlla il metodo in sottoclasse (metodo sovrascritto se presente), se non disponibile utilizza metodo super-classe.

0

override significa ridefinire un metodo dalla superclasse all'interno di una sottoclasse con la stessa firma del metodo. Nel tuo caso, il metodo getTyreCost() non è stato sovrascritto, non hai ridefinito il metodo nella sottoclasse, quindi non sarà necessario utilizzare super.getTyreCost(), solo getTyreCost() (proprio come lo super.getTyreCost() farà lo stesso). La parola chiave super viene utilizzata quando un metodo è stato sovrascritto e si desidera che una chiamata al metodo all'interno della sottoclasse venga implementata nella superclasse.

3

Si sta facendo la strada giusta non utilizzando la parola chiave super per l'accesso a getTyreCost.

Ma è necessario impostare i membri privati ​​e utilizzare solo il metodo getter.

L'utilizzo della parola chiave super deve essere riservata ai costruttori e ai metodi sovrascritti che devono chiamare esplicitamente il metodo genitore.

+0

Buon posto (questo era solo un esempio che ho scritto come parte della domanda). I membri ora sono aggiornati e impostati come privati. – Jonny

2

Ciò dipenderà dal modo in cui si intende utilizzare il codice. Se si specifica super.getTyreCost() e successivamente si esegue l'override del metodo. Continuerai a chiamare il metodo sulla superclasse, non sulla versione sostituita.

A mio parere, la chiamata a super potrebbe causare più confusione in seguito, quindi è probabilmente meglio specificata solo se si ha un'esigenza esplicita di farlo. Tuttavia, per il caso che hai presentato qui, non ci saranno differenze di comportamento.

2

Dipende dalle vostre esigenze e dai vostri desideri. L'utilizzo di super obbliga la compilazione/applicazione a ignorare qualsiasi potenziale metodo nella classe corrente.Se si desidera comunicare che si desidera utilizzare solo il metodo del genitore, è opportuno utilizzare super. Inoltre, impedirà a future modifiche della classe di sovrascrivere accidentalmente il metodo genitore, rovinando così la logica prevista.

Tuttavia, questi casi sono abbastanza rari. L'uso di Super ovunque all'interno della tua classe porterà ad un confuso codice ingombrante &. Nei casi più generali, basta chiamare il metodo all'interno della propria classe e consentire al compilatore/jvm di determinare quale metodo (super o locale) debba essere chiamato è più appropriato. Permette anche di sovrascrivere/modificare/manipolare i valori di ritorno del super in modo pulito.

0

Tecnicamente, quello che viene invocato in questo caso è la versione ereditata, per cui l'implementazione viene effettivamente fornita dalla classe padre.

Ci possono essere scenari in cui è necessario utilizzare la parola chiave super. per esempio. se il metodo Car aveva sostituito quel metodo, per fornire un'implementazione diversa di se stesso, ma era necessario richiamare l'implementazione fornita dalla classe padre, si avrebbe utilizzato la parola chiave super. In tal caso, non puoi permetterti di omettere la parola chiave super perché se lo facessi, invocheresti l'implementazione fornita dalla classe figlio stessa.

+0

Voto precedente? Perché?Downvoter, ti preghiamo di lasciare un commento. Potrei essere in grado di imparare qualcosa. –

+2

Ero io! Sentivo che "che tu lo usi o meno, non fa alcuna differenza" potrebbe essere fuorviante, specialmente nel caso di ulteriori tentativi di ereditare e scavalcare. È vero, finisci la frase con "in questo caso" che lo rende un po 'accurato, ma continuo a pensare che possa essere fuorviante/confusionario. Ridefiniscilo un po 'e sarò felice di non-down-vote! –

+0

@RichardJPLeGuen: ho riformulato la mia risposta e rimosso la parte fuorviante. Se qualcosa è ancora fuorviante, fammi sapere che sarei più che felice di modificare. +1 per il commento. –

Problemi correlati