2010-08-11 27 views
31

Diciamo che ho tre classi A, B e C.chiamata metodo di classe super super

  • B si estende Un
  • C si estende B

Tutti hanno un metodo public void foo() definito.

Ora dal metodo foo() di C voglio invocare il metodo foo() di A (NON il suo metodo di genitore B ma il metodo di super super classe A).

Ho provato super.super.foo();, ma è una sintassi non valida. Come posso ottenere questo?

+1

Solo perché qualcuno dovrebbe chiedere, perché C estende B se sembra che voglia estendere A direttamente? (Immagino ci siano altre parti su cui stai facendo affidamento sulle funzionalità di B, o qualcosa del genere) –

+0

A foo() può essere chiamato da C usando super.foo() solo se B non sovrascrive il comando A foo(). – YoK

+1

_Efficace Java 2nd Edition, elemento 16: composizione preferita su ereditarietà_. Inoltre, controlla lo schema del decoratore; potrebbe adattarsi meglio alle tue esigenze. – polygenelubricants

risposta

30

Non è nemmeno possibile utilizzare la riflessione. Qualcosa di simile

Class superSuperClass = this.getClass().getSuperclass().getSuperclass(); 
superSuperClass.getMethod("foo").invoke(this); 

porterebbe a un InvocationTargetException, perché anche se si chiama il metodo foo-sul superSuperClass, sarà ancora utilizzare C.foo() quando si specifica "questo" in Invoke. Questa è una conseguenza del fatto che tutti i metodi Java sono metodi virtuali.

Sembra che tu abbia bisogno di aiuto dalla classe B (ad esempio definendo un metodo superFoo(){ super.foo(); }).

Detto questo, sembra un problema di progettazione se si prova qualcosa di simile, quindi sarebbe utile darci un po 'di background: Perché è necessario fare questo?

+1

Non era il mio requisito. Stavo solo pensando fuori di testa tutte le possibilità di giocare con l'ereditarietà e ho questa domanda. Grazie .. Ho ricevuto la risposta – Harish

+0

Beh, ho bisogno di farlo perché la super classe ha la precedenza sulla super-classe super in un modo che non voglio .. ed è una libreria ... quindi voglio chiamare quella da super super classe ... forse prendere il codice sorgente del metodo della super super classe e scavalcare di nuovo risolve questo? – xdevs23

+0

Ovviamente puoi scrivere nel tuo metodo quello che vuoi, quindi in questo caso la copia del codice dovrebbe funzionare. Tuttavia, se la super-super-classe usa campi o metodi privati ​​o pacchetti privati ​​in 'foo()', è necessario riflettere per accedervi (e ovviamente non si è fortunati se è presente un responsabile della sicurezza). Inoltre, se il codice originale 'foo()' rende 'super' stesso se stesso, non funzionerebbe neanche. – Landei

0

Non è possibile, siamo limitati a chiamare solo le implementazioni della superclasse.

+0

(ero troppo impressionato da Aarons ora eliminato risposta che Ho cancellato il mio due secondi dopo la pubblicazione;) - non lo ha eliminato anche se ora sono disponibili risposte molto migliori) –

19

Non è possibile - perché potrebbe interrompere l'incapsulamento.

Sei in grado di chiamare il metodo del superclasse perché si presume che si sa che cosa si rompe l'incapsulamento in proprio di classe, e di evitare che ... ma non si sa quali regole superclasse è far rispettare - in modo da non può semplicemente bypassare un'implementazione lì.

+0

Dispari .. Ricordo che c'era un modo per chiamare Object.toString() anche se toString() è stato sovraccaricato da una superclasse. Ma "Type.this" non viene compilato. : -/ –

+1

@Aaron: Non sono sicuro di Object.toString() - stavi pensando a 'System.identityHashCode'? –

+0

Mai usato, sono abbastanza sicuro che fosse toString(). Object.super.toString() non funziona neanche. Forse era un bug in una versione precedente di Java o qualcosa del genere. –

3

Non è possibile farlo in modo semplice.

Questo è ciò che penso che si può fare:

Avere un bool nella classe B. Ora è necessario chiamare foo di B da C come [super foo], ma prima di fare questo impostare il bool true. Ora in B's foo controlla se il bool è vero, quindi non eseguire alcun passo e chiama semplicemente A's foo.

Spero che questo aiuti.

+6

Questo è il più selvaggio trucco Java mai :) –

+2

La risposta di Jon Skeet è la migliore: questo tipo di funzionalità non deve essere abilitato perché interrompe l'incapsulamento. Invece di rivolgersi a _HOW_ per fare qualcosa di simile, dovremmo rivolgerci al _WHY_ chiunque vorrebbe fare qualcosa del genere (e distruggere quell'argomento per violare i principi dell'OOP). – polygenelubricants

+2

@Nikita Rybak: Le persone chiedono cose che non dovrebbero essere poste. Da qui le risposte che non dovrebbero essere date;) –

0

I smell qualcosa di sospetto qui.

Sei sicuro di non aver spinto troppo la busta "solo perché dovresti essere in grado di farlo"? Sei sicuro che questo sia il miglior modello di design che puoi ottenere? Hai provato a rifarlo?

0

Ho avuto un problema in cui una superclasse avrebbe chiamato un metodo di prima classe che era stato sovrascritto. Questa è stata la mia soluzione alternativa ...

// QUESTO fallirebbe CHIAMATA SUPERCLASSE metodi come A1() sarebbe invocare top class METODO

class foo1{ 
public void a1(){ 
    a2(); 
    } 
public void a2(){} 
} 
class foo2 extends foo1{ 
{ 
public void a1(){ 
//some other stuff 
super.a1(); 
} 
public void a2(){ 
//some other stuff 
super.a2(); 
} 

// Ciò garantisce la DESTRA SUPERCLASSE metodi vengono chiamati // i metodi pubblici chiamare solo i metodi privati ​​in modo che tutti i metodi pubblici possono essere ignorati senza influire sulla funzionalità della superclasse.

class foo1{ 
public void a1(){ 
    a3();} 
public void a2(){ 
    a3();} 
private void a3(){ 
//super class routine 
} 
class foo2 extends foo1{ 
{ 
public void a1(){ 
//some other stuff 
super.a1(); 
} 
public void a2(){ 
//some other stuff 
super.a2(); 
} 

Spero che questo aiuti. :)

+0

questo in realtà non risponde alla domanda. per favore rileggi la domanda – Aboutblank

0

Prima di utilizzare l'API di riflessione, pensate al suo costo.

È semplicemente facile da fare. Ad esempio:

C sottoclasse di sottoclasse B e B di A. Entrambe le tre hanno metodo methodName() ad esempio.

public abstract class A { 

    public void methodName() { 
    System.out.println("Class A"); 
    } 

} 


public class B extends A { 

    public void methodName() { 
     super.methodName(); 
     System.out.println("Class B"); 
    } 

    // Will call the super methodName 
    public void hackSuper() { 
     super.methodName(); 
    } 

} 

public class C extends B { 

    public static void main(String[] args) { 
     A a = new C(); 
     a.methodName(); 
    } 

    @Override 
    public void methodName() { 
     /*super.methodName();*/ 
     hackSuper(); 
     System.out.println("Class C"); 
    } 

} 

classe Run C in uscita sarà: Classe A Classe C

Invece di uscita: Classe A Classe B Classe C

2

per citare un precedente risposta "Si puo' t - perché romperebbe l'incapsulamento. " a cui vorrei aggiungere che:

Tuttavia esiste un caso in cui è possibile, vale a dire se il metodo è static (public o protected). Non puoi overwrite the static method.

Avere un metodo public static è banale per dimostrare che si può effettivamente fare questo.

Per protected tuttavia, è necessario all'interno di uno dei propri metodi eseguire un cast su qualsiasi superclasse nel percorso di ereditarietà e il metodo della superclasse verrà chiamato.

Questo è il caso angolo sto esplorando nella mia risposta:

public class A { 
    static protected callMe(){ 
     System.out.println("A"); 
    } 
} 

public class B extends A { 
    static protected callMe(){ 
     System.out.println("B"); 
    } 
} 

public class C extends B { 
    static protected callMe(){ 
     System.out.println("C"); 
     C.callMe(); 
    } 

    public void accessMyParents(){ 
     A a = (A) this; 
     a.callMe(); //calling beyond super class 
    } 
} 

La risposta rimane No, ma volevo solo mostrare un caso in cui è possibile, anche se probabilmente non avrebbe alcun senso e è solo un esercizio.

2

Sì, puoi farlo. Questo è un hack. Cerca di non progettare il tuo programma in questo modo.

class A 
{ 
    public void method() 
    { /* Code specific to A */ } 
} 

class B extends A 
{ 
    @Override 
    public void method() 
    { 
     //compares if the calling object is of type C, if yes push the call to the A's method. 
     if(this.getClass().getName().compareTo("C")==0) 
     { 
      super.method(); 
     } 
     else{ /*Code specific to B*/ } 

    } 
} 

class C extends B 
{ 
    @Override 
    public void method() 
    { 
     /* I want to use the code specific to A without using B */ 
     super.method(); 

    } 
} 
+0

Questo è chiamato Inversion of Control! –

Problemi correlati