2015-05-26 31 views
7

Wiem, że jest to bardzo proste pytanie, ale pracuję w Pythonie od dłuższego czasu i teraz muszę wrócić do Java, wydaje mi się, że mam problemy zmieniając chip i owijając głowę wokół podstawowego polimorfizmu Javy.Identyfikacja podpisu metody za pomocą dziedziczonych klas w abstrakcyjnych metodach Java

Czy można nadpisać (zaimplementować, by być precyzyjnym) metodę klasy "abstract w Javie, używając jednej z dziedziczonych klas jako argumentu?

Pozwól mi wyjaśnić w bardzo prosty przykład (po „prawie oficjalny”example z kształtami)

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"); 
    } 
} 

Czy istnieje jakiś sposób mający Java identyfikacji metodę draw w klasie CircleDrawer jak wdrożenie abstrakcji draw w ShapeDrawer? (Klasa Circle rozciąga się od Shape po wszystkich)

Inaczej umieścić: Co chciałbym jest to, że metoda klasy CircleDrawerdraw akceptuje tylko instancje typu Circle, ale w tym samym czasie, chciałbym powiedzieć kompilator Java, który jest void draw(Circle c), jest w rzeczywistości implementacją abstrakcyjnej metody znajdującej się w jej klasie nadrzędnej.

Z góry dziękuję.

+1

Może po prostu czytam to źle, ale jeśli to nie jest to, czego chcesz, możesz podać przykład tego, czego chcesz? – Aify

+0

@Aify, edytowałem pytanie opisujące to, co chciałbym osiągnąć. Mam nadzieję, że teraz jest jaśniej? Daj mi znać, jeśli nie jest. – BorrajaX

+1

Nie zapomnij wyłączyć zasilania, zanim wyrzucisz ten chip. – markspace

Odpowiedz

7

można rozwiązać problemu za pomocą leków generycznych:

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

Nie, metoda podpisów Java musi być identyczna, nie można korzystać z podtypów, lub będziesz przeciążyć metodę zamiast przesłanianie go.

Możesz powrócić podtypu, ale to wszystko, a typy zwrotu nie są częścią sygnatury metody.

4

Nie możesz i istnieje bardzo dobry powód, dla którego nie możesz. Weź tę deklarację

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

Teraz trochę kodu, który odbiera ShapeDrawer i stara się go używać:

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

Kod ten powinien działać, ponieważ deklaracja ShapeDrawer obietnic, że kto realizuje będzie dostarczać metody nazywanej draw() i ta metoda może poradzić sobie z każdym Shape.

Ale jeśli mogli to zrobić:

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

Że nie będzie już uznać za prawdziwe, twój CircleDrawer byłby w stanie spełnić obietnicę, że może poradzić sobie z każdym Shape.


jednak wyobrazić tę deklarację:

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

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

to będzie działać?

Tak, to (pod warunkiem, że używasz Java 5 lub nowszy), ponieważ w przeciwieństwie do pierwszej deklaracji, co ShapeCreator obiecuje, że będzie to miało metodę zwaną create(), która będzie zwracać Shape. Od Circle jest Shape, podklasa ShapeCreator może zdecydować się na powrót tylko Circle s, obietnice nie są zepsute.


Jak osiągnąć to, czego chcesz? Patrz: loonytune's answer :)

1

Nie technicznie, ale możesz zrobić z niego hakowanie dla określonej funkcji.

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

To jest OK, ale w gruncie rzeczy to samo, co podany przykład generyków. Wolałbym generycznych, jeśli mam coś takiego zrobić. – markspace

+0

Jest blisko, ale nie na tyle blisko, by powiedzieć, że jest taki sam. Robiąc to w ten sposób, nadal możesz technicznie przekazywać inne kształty i wykonywać inne czynności - np. Wydrukuj "to nie jest krąg" lub coś w tym rodzaju. Ale kupuj używając Generics, nie możesz nawet nazwać go czymś, co nie jest Kręgiem. – Aify

+0

Wewnętrznie, wszystkie rodzaje generyczne to test typu instancji podobny do tego, co zrobiłeś. Jednak kompilator nie powinien * uniemożliwiać * przekazywania niczego, co nie jest Kręgiem, aw większości przypadków jest to duża wygrana. – markspace