2013-02-01 14 views
6

Jestem bardzo zdezorientowany z nadpisującymi konstruktorami. Konstruktor nie może być przesłonięta jest wynikiem tego, co mogę dostać kiedy szukałem go w google moje pytanie jestNadpisywanie konstruktorów

public class constructorOverridden { 

    public static void main(String args[]) { 
     Sub sub = new Sub(); 
     sub.test(); 
    } 
} 

class Super { 
    Super() { 
     System.out.println("In Super constructor"); 
     test(); 
    } 

    void test() { 
     System.out.println("In Super.test()"); 
    } 
} 

class Sub extends Super { 
    Sub() { 
     System.out.println("In Sub constructor"); 
    } 

    void test() { // overrides test() in Super 
     System.out.println("In Sub.test()"); 
    } 
} 

gdy uruchamiam to mam wynik jako

In Super constructor 
In Sub.test() 
In Sub constructor 
In Sub.test() 

pls zwrócić uwagę na metodę badawczą w podklasie jest wykonywany. Czy pokazuje, że konstruktor Superclass został nadpisany. Czy to prawda?

Odpowiedz

19

Konstruktory nie są polimorficzne - w żadnym razie nie można ich zastąpić . Tworzysz nowych konstruktorów w podklasie, a każdy konstruktor podklasy musi łączyć się łańcuchowo (prawdopodobnie pośrednio) z konstruktorem superklasy. Jeśli nie jawnie łańcuch do konstruktora, niejawne wywołanie konstruktora nadklasy bez parametrów jest wstawiane na początku korpusu konstruktora podklasy.

Teraz pod względem nadpisywania metody - obiekt jest jego "ostatecznego typu" od samego początku, w tym podczas wykonywania konstruktora nadklasy. Jeśli więc wydrukujesz getClass() w kodzie konstruktora Super, na wyjściu nadal będzie widoczny Sub. Efektem tego jest nadpisana metoda (to jest Sub.test), mimo że konstruktor Sub nie został jeszcze wykonany.

Jest to zasadniczo zły pomysł, a prawie zawsze należy unikać wywoływania potencjalnie nadpisane metody w konstruktorów - lub dokument bardzo wyraźnie, że dzieje się w przypadku (tak, że kod podklasa ma świadomość, że może” t polegać na zmiennych, które zostały odpowiednio zainicjowane itp.).

+0

Następnie, jakie podejście należy zastosować, unikając "wywoływania nadpisanych metod w konstruktorach"? Co starałem się osiągnąć jest podstawowy przepływ w konstruktorze super klasy wywoływanie metod abstrakcyjnych init(), build(), a następnie fill(). Tak więc wszystkie podklasy muszą przejść ten sam przepływ! – Akshat

+0

@Akshat: Cóż, brzmi to tak, jakby należało do kategorii "bardzo jasno dokumentować". Zazwyczaj * istnieje * sposób projektowania wokół tego, ale trudno jest podać ogólny przepis. –

+0

Jeśli mógłbyś podać link do tych sposobów, byłoby wspaniale! – Akshat

3

Pierwsza niejawna linia konstruktora to połączenie z Super(). Właśnie dlatego otrzymujesz te wyniki.

3

Zgadza się. Podczas tworzenia podklasy, konstruktor nadklasy jest wywoływany jako pierwszy, a następnie każdy kolejny konstruktor w hierarchii.

W powyższym przykładzie konstruktor nadklasy wywołuje metodę nadpisywaną (test()). Działa to, ale jest potencjalnie niebezpieczne, ponieważ konstruktor podklasy nie został wywołany, a twoja podklasa nie zostanie w pełni zainicjowana. Z tego powodu wywoływanie nadpisywanych (lub zastępowalnych) metod w konstruktorze nie jest dobrą praktyką.

2

to nie nadpisywanie super klasy konstruktora i konstruktora nie może być przesłonięte, może być przeciążone.

Gdy utworzysz obiekt klasy potomnej super klasa zostanie utworzona jako pierwsza, zostanie utworzona klasa podrzędna. To jest jak Dziecko nie może istnieć bez rodzica.

Kompilator automatycznie wywoła konstruktor superklasy z konstruktora klasy podrzędnej.

Sub() { 
    super(); 
    System.out.println("In Sub constructor"); 
} 
4

Nie można przesłonić konstruktora, ponieważ konstruktor jest wywoływany przez nazwę klasy, którą konstruuje. Jak utworzyć inną klasę z tym samym konstruktorem? Ponadto klasa potomna nie dziedziczy konstruktorów od swoich obiektów nadrzędnych.

Jeżeli konstruktor rodzic ma jakąś ważną inicjację, może być wywoływana z dzieckiem za pomocą konstruktora Super:

class Err extends Throwable { 
    Err(String message) { 
     super(message); // Call the constructor of Throwable. 
     .. 

Rodzic klasy konstruktor jest też zawsze nazywany. Jeśli sam nie wywołasz żadnego, konstruktor bez parametrów jest wywoływany automatycznie przed wejściem do konstruktora klasy pochodnej. Jeśli rodzic nie ma konstruktora bez parametrów i nie wywołuje żadnego, raportowany jest błąd czasu kompilacji.