Java Constructor

Zastanawiałem się dlaczego w Javie konstruktory nie są dziedziczone? Wiesz kiedy masz taką klasę:

public class Super {

  public Super(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
    this.serviceA = serviceA;
    //etc
  } 

}

Później, gdy dziedziczysz z Super, java będzie narzekać, że nie ma zdefiniowanego konstruktora domyślnego. Rozwiązaniem jest oczywiście coś w stylu:

public class Son extends Super{

  public Son(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
    super(serviceA,serviceB,serviceC);
  }

}

Ten kod jest powtarzalny, nie suchy i bezużyteczny (IMHO)... więc to rodzi pytanie ponownie:

Dlaczego java nie obsługuje dziedziczenia konstruktorów? Czy jest jakaś korzyść z tego spadek?

Author: Michael Celey, 2009-10-29

10 answers

Załóżmy, że konstruktorybyły dziedziczone... wtedy, ponieważ każda klasa w końcu wywodzi się od obiektu, każda klasa kończy się konstruktorem bez parametru. To zły pomysł. Czego dokładnie można się spodziewać:

FileInputStream stream = new FileInputStream();
Do zrobienia?

Teraz potencjalnie powinien być sposób na łatwe tworzenie konstruktorów" przelotowych", które są dość powszechne, ale nie sądzę, że powinny być domyślne. Parametry potrzebne do zbudowania podklasy często różnią się od te wymagane przez superklasę.

 185
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 15:09:42

Kiedy dziedziczysz z Super, tak się dzieje w rzeczywistości:

public class Son extends Super{

  // If you dont declare a constructor of any type, adefault one will appear.
  public Son(){
    // If you dont call any other constructor in the first line a call to super() will be placed instead.
    super();
  }

}

Więc to jest powód, ponieważ musisz wywołać swój unikalny konstruktor, ponieważ"Super" nie ma domyślnego.

Teraz próbuję odgadnąć, dlaczego Java nie obsługuje dziedziczenia konstruktora, prawdopodobnie dlatego, że konstruktor ma sens tylko wtedy, gdy mówi o konkretnych instancjach, i nie powinieneś być w stanie stworzyć instancji czegoś, gdy nie wiesz, jak to jest zdefiniowane (przez polimorfizm).

 27
Author: David Santamaria,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-25 14:19:12

Ponieważ konstruowanie obiektu podklasy może być wykonane w inny sposób niż budowa klasy nadrzędnej. Możesz nie chcieć, aby klienci podklasy mogli wywoływać pewne konstruktory dostępne w klasie nadrzędnej.

Głupi przykład:

class Super {
    protected final Number value;
    public Super(Number value){
        this.value = value;
    }
}

class Sub {
    public Sub(){ super(Integer.valueOf(0)); }
    void doSomeStuff(){
        // We know this.value is an Integer, so it's safe to cast.
        doSomethingWithAnInteger((Integer)this.value);
    }
}

// Client code:
Sub s = new Sub(Long.valueOf(666L)): // Devilish invocation of Super constructor!
s.doSomeStuff(); // throws ClassCastException

Lub jeszcze prościej:

class Super {
    private final String msg;
    Super(String msg){
        if (msg == null) throw new NullPointerException();
        this.msg = msg;
    }
}
class Sub {
    private final String detail;
    Sub(String msg, String detail){
        super(msg);
        if (detail == null) throw new NullPointerException();
        this.detail = detail;
    }
    void print(){
        // detail is never null, so this method won't fail
        System.out.println(detail.concat(": ").concat(msg));
    }
}
// Client code:
Sub s = new Sub("message"); // Calling Super constructor - detail is never initialized!
s.print(); // throws NullPointerException

Z tego przykładu widać, że potrzebujesz jakiegoś sposobu zadeklarowania, że "chcę dziedziczyć te konstruktory" lub "chcę dziedziczyć wszystkie konstruktory z wyjątkiem tych", a następnie trzeba również określić domyślne preferencje dziedziczenia konstruktora na wypadek, gdyby ktoś dodał nowy konstruktor w klasie nadrzędnej... albo możesz po prostu wymagać powtórzenia konstruktorów z klasy nadrzędnej, jeśli chcesz je "odziedziczyć", co prawdopodobnie jest bardziej oczywistym sposobem na to.

 11
Author: gustafc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-13 19:40:24

Ponieważ konstruktory są szczegółem implementacji - nie są czymś, co użytkownik interfejsu/klasy nadrzędnej może w ogóle wywołać. Do czasu, gdy otrzymają instancję, została ona już skonstruowana; i odwrotnie, w momencie konstruowania obiektu nie ma z definicji żadnej zmiennej, do której jest obecnie przypisana.

Pomyśl, co to znaczy wymusić na wszystkich podklasach dziedziczenie konstruktora. Argumentuję, że jest jaśniejsze przekazywanie zmiennych bezpośrednio niż dla Klasa to "magicznie" ma konstruktor z określoną liczbą argumentów tylko dlatego, że rodzic ma.

 5
Author: Andrzej Doyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 15:05:28

Konstruktory nie są polimorficzne.
Gdy masz do czynienia z już zbudowanymi klasami, możesz mieć do czynienia z zadeklarowanym typem obiektu lub którąkolwiek z jego podklas. Do tego przydaje się dziedziczenie.
Konstruktory są zawsze wywoływane na określonym typie, np. new String(). Hipotetyczne podklasy nie odgrywają w tym żadnej roli.

 2
Author: Rik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 15:09:26

Odpowiedź Dawida jest prawidłowa. Chciałbym dodać, że być może otrzymujesz znak od Boga, że twój projekt jest popaprany, i że " Son "nie powinien być podklasą "Super", ale zamiast tego Super ma pewne szczegóły implementacji najlepiej wyrażone przez posiadanie funkcjonalności, którą zapewnia Son, jako rodzaj strategii.

EDIT: odpowiedź Jona Skeeta jest niesamowita.

 2
Author: Jonathan Feinberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 21:16:43

Ponieważ Klasa (super)musi mieć pełną kontrolę nad jej budową. Jeśli programista zdecyduje, że nie ma sensu podawać domyślnego konstruktora (bez args) w ramach kontraktu klasy, kompilator nie powinien go dostarczać.

 0
Author: David R Tribble,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 23:19:17

Zasadniczo dziedziczysz konstuktory w tym sensie, że możesz po prostu wywołać super, JEŚLI i kiedy jest to właściwe, to po prostu byłoby podatne na błędy z powodów, o których inni wspominali, gdyby stało się to domyślnie. Kompilator nie może zakładać, kiedy jest odpowiedni, a kiedy nie.

Zadaniem kompilatora jest zapewnienie jak największej elastyczności przy jednoczesnym zmniejszeniu złożoności i ryzyka niezamierzonych skutków ubocznych.

 0
Author: clearlight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-01 08:23:28

Nie znam żadnego języka, w którym podklasy dziedziczą konstruktory (ale nie jestem zbytnio programistycznym polyglottem).

Oto dyskusja na temat tego samego pytania dotyczącego C#. Ogólny konsensus wydaje się być taki, że skomplikowałoby to język, wprowadziłoby potencjalne nieprzyjemne skutki uboczne do zmian w klasie bazowej i ogólnie nie powinno być konieczne w dobrym projekcie.

 -1
Author: Michael Borgwardt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 15:12:11

Klasa pochodna nie jest tą samą klasą co jej klasa bazowa i możesz, ale nie musisz dbać o to, czy któryś z członków klasy bazowej został zainicjowany w czasie budowy klasy pochodnej. Jest to określenie dokonane przez programistę, a nie przez kompilator.

 -1
Author: ChadNC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 16:07:52