2012-11-10 15 views
11

Diciamo che Java ha queste classi gerarchiche:Java eredità vs C# eredità

class A 
{ 
} 
class B extends A 
{ 
    public void m() 
    { 
     System.out.println("B\n"); 
    } 
} 
class C extends B 
{ 
    public void m() 
    { 
     System.out.println("C\n"); 
    } 
} 
class D extends C 
{ 
    public static void main(String[] args) 
    { 
     A a = new D(); 
     // a.m(); // doesn't work 
     B b = new D(); 
     b.m(); 
     C c = new D(); 
     c.m(); 
     D d = new D(); 
     d.m(); 
    } 
} 

Questo è il (non vedenti) la duplicazione dello stesso codice in C#:

using System; 
class A 
{ 
} 
class B : A 
{ 
    public void M() 
    { 
     Console.WriteLine("B"); 
    } 
} 
class C : B 
{ 
    public void M() // I need to use public new void M() to avoid the warning 
    { 
     Console.WriteLine("C"); 
    } 
} 
class D : C 
{ 
    public static void Main(String[] args) 
    { 
     A a = new D(); 
     // a.M(); // doesn't work  
     B b = new D(); 
     b.M(); 
     C c = new D(); 
     c.M(); 
     D d = new D(); 
     d.M(); 
    } 
} 

Quando eseguo il Java codice, ho ottenuto C-C-C mentre C# restituisce B-C-C.

Per me risultato C# 's ha più senso, come riferimento B invoca il proprio metodo.

  • Qual è la logica dietro la decisione del designer Java di stampare C-C-C anziché B-C-C? Voglio dire, perché il riferimento B usa il metodo di override in C? Qual è il vantaggio di questo approccio?
  • Come posso cambiare il codice Java per stampare B-C-C proprio come C# fa? Voglio dire, come posso insegnare a java a invocare il metodo dell'esatto riferimento che usa?
  • Come posso cambiare il codice C# per stampare C-C-C? Voglio dire, come posso insegnare a C# a invocare il metodo di override?
+2

Si tratta di un semplice problema di progettazione - Java utilizza la spedizione dinamica di default, mentre C# non lo fa, per ottenere dinamica invio in C# è necessario dichiarare un metodo virtuale e indicare che il metodo prevalente lo sta effettivamente sovrascrivendo. – amit

+1

Le classi D e A non hanno alcuna funzione qui.Puoi ometterli per un campione più breve (più chiaro). –

risposta

10

È per la definizione virtual function:

una funzione virtuale o metodo virtuale è una funzione o metodo cui comportamento può essere ignorato all'interno di una sottoclasse da una funzione con la stessa firma. Questo concetto è una parte molto importante della porzione di polimorfismo della programmazione orientata agli oggetti (OOP).

In C#, si dovrebbe dichiarare il metodo come virtuale, al fine di essere ignorato, come mostrato in MSDN:

Poiché il metodo M non è virtuale, esso verrà eseguito b.M() anche se b variabile è in realtà un D istanza.

In Java, ogni metodo è virtuale per impostazione predefinita, in modo da quando si sostituisce un metodo (anche senza il @Override annotazione) il comportamento del b.M() sarà il d.M() che eredita il comportamento c.M() metodo.

Come posso modificare il codice Java per stampare B-C-C come fa C#? Voglio dire, come posso insegnare a java a invocare il metodo dell'esatto riferimento che usa?

Semplicemente non è possibile farlo in Java. Il metodo M nella classe C sostituisce il metodo M in B. L'aggiunta del modificatore final a o ad altri B bambini non può sostituire il metodo M().

Come posso modificare il codice C# per stampare C-C-C? Voglio dire, come posso insegnare a C# a invocare il metodo di override?

cambiare il metodo M in B classe per virtual e override in C classe:

class B : A 
{ 
    public virtual void M() 
    { 
     Console.WriteLine("B"); 
    } 
} 
class C : B 
{ 
    public override void M() // I need to use public new void M() to avoid the warning 
    { 
     Console.WriteLine("C"); 
    } 
} 
6
  1. In Java tutti metodi sono virtuali di default. E i metodi nelle classi derivate sovrascrivono i metodi dalla base. In C# non lo sono.

  2. Sembra come non si può fare questo. Ma puoi impedire alle classi derivate di ignorare questo metodo dichiarandolo come final.

  3. Dichiarare questo metodo con la parola chiave virtual nella classe base e con override in derivato.

+0

+1 per la risposta, ma sarebbe bello se si riformula il 3 ° punto con C# che viene specificato con esso – exexzian

+3

Semplicemente non è possibile dichiarare B.m() come finale in quanto impedirà a C.m() di sovrascriverlo. – prosseek

+0

@prosseek davvero. colpa mia. modificato. – 2kay

0

Qual è la logica dietro la decisione del progettista Java per stampare C-C-C invece di B-C-C? Voglio dire, perché il riferimento B usa il metodo di override in C? Qual è il vantaggio di questo approccio?

Guarda che chiami il metodo dall'oggetto di classe D che ha ereditato il metodo M dalla classe C. Il tipo di riferimento non ha importanza in Java: la parte importante è quale classe ha oggetto di riferimento.

1

Qual è la logica dietro la decisione del designer Java di stampare C-C-C anziché B-C-C?

Java rende i metodi virtuali per impostazione predefinita. In passato c'era la comprensione che questa era una buona pratica, e al tempo della nascita di Giava era forse al culmine di quella comprensione.

In questi giorni - mentre molti non tengono ad essa - c'è anche più resistenza ad esso (in particolare per quanto metodi virtuali aprono la classe a scelte di implementazione sottoclasse inaspettate).

(NB. Non c'è giusto o sbagliato qui, ogni approccio ha i suoi vantaggi e svantaggi.)

Come posso cambiare il codice Java per stampare B-C-C come C# non?

Dichiararli final.

Come posso modificare il codice C# per stampare C-C-C?

dichiararli virtual o abstract nella classe che li definisce (B in questione), e override in classi figlie.

+0

È necessario contrassegnare il metodo 'C' con' override'. – CodesInChaos

+0

@CodesInChaos infatti, anche perso quell'astratto implica virtuale. – Richard