2015-05-26 10 views
7

So che questa è una domanda molto semplice, ma ho lavorato in Python per un periodo piuttosto lungo e ora che devo tornare a Java, mi sembra di avere problemi cambiando il chip e avvolgendomi attorno al polimorfismo di base di Java.Identifica la firma del metodo utilizzando classi ereditate nei metodi astratti di Java

È possibile sovrascrivere (implementare, per essere precisi) un metodo di classe 'abstract in Java utilizzando una delle classi ereditate come argomento?

Mi spiego con un esempio molto semplice (in seguito alla "quasi ufficiale"example con forme)

class Shape {} 
class Circle extends Shape {} 
class Triangle extends Shape {} 

abstract class ShapeDrawer { 
    abstract void draw(Shape s); 
}      
class CircleDrawer extends ShapeDrawer { 
    void draw(Circle c){ 
     System.out.println("Drawing circle"); 
    } 
} 

non v'è alcun modo di avere Java identificare il metodo draw nella classe CircleDrawer come l'implementazione dell'aspetto draw in ShapeDrawer? (La classe Circle si estende da Shape dopo tutto)

altrimenti presentati: Quello che mi piace è che il metodo della classe CircleDrawerdraw accetta solo le istanze di tipo Circle, ma allo stesso tempo, vorrei dire il compilatore Java che lo void draw(Circle c) è in realtà l'implementazione del metodo astratto abstract void draw(Shape s) situato nella sua classe genitore.

Grazie in anticipo.

+1

Forse sto leggendo questo errore, ma se questo non è ciò che vuoi puoi fornire un esempio di ciò che vuoi? – Aify

+0

@Aify, ho modificato la domanda descrivendo cosa avrei voluto ottenere. Speriamo sia più chiaro ora? Fammi sapere se non lo è. – BorrajaX

+1

Non dimenticare di spegnere prima di estrarre il chip. – markspace

risposta

7

È possibile risolvere il problema mediante farmaci generici:

public abstract class ShapeDrawer<T extends Shape> { 
    public abstract void draw(T shape); 
} 

public class CircleDrawer extends ShapeDrawer<Circle> { 
    public void draw(Circle circle) { ... } 
} 
1

No, metodo Java firme devono corrispondere esattamente, non è possibile utilizzare i sottotipi, o ti sovraccaricare un metodo, invece di rilevante esso.

È possibile restituire un sottotipo, ma il gioco è fatto e i tipi restituiti non fanno parte della firma del metodo.

4

Non puoi e c'è una buona ragione per cui non puoi. Prendete questa dichiarazione

public abstract class ShapeDrawer { 
    public abstract void draw(Shape s); 
} 

Ora prendete un po 'di codice che riceve un ShapeDrawer e cerca di usarlo:

public void foo(ShapeDrawer drawer, Shape shape) { 
    drawer.draw(shape); 
} 

Questo codice dovrebbe funzionare perché la dichiarazione di ShapeDrawer promesse che chi implementa fornirà un metodo chiamato draw() e tale metodo può gestire qualsiasi Shape.

Ma se si fosse permesso di compiere questa:

public class CircleDrawer extends ShapeDrawer { 
    public void draw(Circle c) {...} 
} 

Che non sarebbe più tenere vero, il tuo CircleDrawer sarebbero in grado di soddisfare la promessa che si può affrontare qualsiasi Shape.


Tuttavia immaginare questa dichiarazione:

public abstract class ShapeCreator { 
    public abstract Shape create(); 
} 

public class CircleCreator extends ShapeCreator { 
    public Circle create() {...} 
} 

Sarebbe questo lavoro?

Sì, sarebbe (a condizione che si utilizza Java 5 o successivo), perché a differenza della prima dichiarazione, ciò ShapeCreator promesse è che avrà un metodo chiamato create(), che restituirà un Shape. Dal momento che Circle è un Shape, una sottoclasse di ShapeCreator può decidere di restituire solo Circle s, nessuna promessa è stata interrotta.


Quindi come si ottiene ciò che si desidera? Vedi loonytune's answer :)

1

Non tecnicamente, ma si può fare un trucco attorno ad esso per la funzionalità specificata.

public abstract ShapeDrawer { 
    public abstract void draw(Shape s); 
}      
public CircleDrawer extends ShapeDrawer { 
    public void draw(Shape s){ 
     if (s instanceof Circle) { 
      System.out.println("Drawing circle"); 
     } 
    } 
} 
+0

Questo è OK, ma sostanzialmente uguale all'esempio generico già fornito. Preferirei i farmaci generici se farò qualcosa del genere. – markspace

+0

È vicino, ma non abbastanza vicino da dire che è lo stesso. Facendolo in questo modo, puoi ancora passare tecnicamente in altre forme e fare altri tipi di gestione, ad esempio: stampa "questo non è un cerchio" o qualcosa del genere. Ma compra con Generics, non ti è nemmeno permesso chiamarlo con qualcosa che non sia un Cerchio. – Aify

+0

Internamente, tutti i generici fanno testare il tipo di istanza simile a quello che hai fatto. Tuttavia, il compilatore dovrebbe * impedire * di passare tutto ciò che non è un Cerchio, e nella maggior parte dei casi è una grande vittoria. – markspace

Problemi correlati