Почему конструктор супер класса вызывается, когда мы объявляем объект подкласса? (Ява)

рассмотрим этот код:

class Test {
    Test() {
        System.out.println("In constructor of Superclass");
    }

    int adds(int n1, int n2) {
        return(n1+n2);
    }

    void print(int sum) {
        System.out.println("the sums are " + sum);
    }
}


class Test1 extends Test {
    Test1(int n1, int n2) {
        System.out.println("In constructor of Subclass");
        int sum = this.adds(n1,n2);
        this.print(sum);
    }

    public static void main(String[] args) {
        Test1 a=new Test1(13,12);
        Test c=new Test1(15,14);
    }
}

Если у нас есть конструктор в супер классе, он будет вызываться каждым объектом, который мы построить для дочернего класса (ex. Объект " a " для класса Test1 вызывает Test1(int n1, int n2), а также Test()).

почему это происходит?

вывод этой программы:

в конструкторе суперкласса

в конструкторе подкласса

суммы 25

в конструкторе суперкласса

в конструкторе подкласса

суммы 29

18 ответов


потому что это гарантирует, что при вызове конструктора он может полагаться на инициализацию всех полей в своем суперклассе.

см. 3.4.4 в здесь


да. Суперкласс должен быть построен до того, как производный класс может быть построен, иначе некоторые поля, которые должны быть доступны в производном классе, не могут быть инициализированы.

маленькое замечание: если вам нужно вызвать явно конструктор супер класса, чтобы передать ему некоторые параметры:

baseClassConstructor(){
    super(someParams);
}

тогда супер конструктор должен быть первым вызовом метода в производный конструктор. Например, это не будет компилироваться:

baseClassConstructor(){
     foo(); 
     super(someParams); // compilation error
}

super () добавляется в каждый конструктор класса автоматически компилятором.

как мы хорошо знаем, конструктор по умолчанию предоставляется компилятором автоматически, но он также добавляет super () для первого оператора.Если вы создаете свой собственный конструктор, и у вас нет this() или super() в качестве первого оператора, компилятор предоставит super () в качестве первого оператора конструктора.

enter image description here


Java классы создаются в следующем порядке:

(во время classload ) 0. инициализаторы для статических элементов и статических блоков инициализаторов, по порядку декларации.

(на каждом новом объекте)

  1. создать локальные переменные для аргументов конструктора
  2. если конструктор начинается с вызова другого конструктора class, оцените Аргументы и рекурсию к предыдущему шагу. Все шаги завершены для этого конструктор, включающий дальнейшую рекурсию конструктор вызывает, прежде чем продолжить.
  3. если суперкласс не был построен выше, постройте суперкласс (используя конструктор no-arg, если он не указан). Как #2, пройдите все эти шаги для суперкласса, включая построение Это суперкласс, прежде чем продолжить.
  4. инициализаторы, например переменные и нестатические блоки инициализаторов, в порядок декларирования.
  5. остальные конструктор.

вот как работает Java. При создании дочернего объекта вызывается супер конструктор (неявно).


подкласс наследует поля от суперкласса(ов) и этих полей есть для создания / инициализации (это обычная цель конструктора: init члены класса, так что экземпляр работает по мере необходимости. Мы знаем, что некоторые люди, но гораздо больше функциональности в этих бедных конструкторах...)


конструктор реализует логику, которая делает объект готовым к работе. Объект может содержать состояние в закрытых полях, поэтому только методы его класса могут получить к ним доступ. Поэтому, если вы хотите, чтобы экземпляр вашего подкласса был действительно готов к работе после вызова конструктора (т. е. все его функции, включая унаследованные от базового класса, в порядке), конструктор базового класса должен быть вызван.

вот почему система работает таким образом.

автоматически конструктор по умолчанию базового класса называемый. Если вы хотите изменить это, вы должны явно вызвать конструктор базового класса путем написания super() в первой строке конструктора подкласса'.


конструктор базового класса будет вызываться перед конструктором производного класса. Это имеет смысл, поскольку гарантирует, что базовый класс будет правильно построен при выполнении конструктора для производного класса. Это позволяет использовать некоторые данные из базового класса при построении производного класса.


когда мы создаем объект подкласса, то должны учитываться все функции-члены и переменные-члены, определенные в суперклассе. Может возникнуть случай, когда некоторая переменная-член может быть инициализирована в некоторых конструкторах суперкласса. следовательно, когда мы создаем объект подкласса, все конструкторы в соответствующем дереве наследования вызываются способом сверху вниз.

в частности, когда переменная определена как защищенный Он всегда будет доступен в подклассе независимо от того, находится ли подкласс в одном пакете или нет. Теперь из подкласса, если мы вызываем функцию суперкласса для печати значения этой защищенной переменной (которая может быть инициализирована в конструкторе суперкласса), мы должны получить правильное инициализированное значение.Следовательно, вызываются все конструкторы суперкласса.

внутренне Java вызывает super () в каждом конструкторе. Итак, каждый подкласс конструктор вызывает конструктор суперкласса с помощью super (), и, следовательно, они выполняются в верхней нижней части.

Примечание : функции могут быть переопределены не переменные.


поскольку вы наследуете свойства базового класса в производный класс, могут возникнуть ситуации, когда конструктор производного класса требует некоторых переменных базового класса для инициализации своих переменных. Поэтому сначала он должен инициализировать переменные базового класса, а затем переменные производного класса. Вот почему Java вызывает первый конструктор базового класса, а затем конструктор производного класса.

а также он не делает никаких sens для инициализации дочернего класса без инициализации родителя класс.


конструктор супер класса в вызывается первым, потому что все методы в программе сначала присутствуют в куче и после компиляции они сохраняются в стеке,из-за чего конструктор супер класса вызывается первым.


простыми словами, если super class имеет параметризованный конструктор, вам нужно явно вызвать super (params) в первой строке вашего конструктора дочернего класса, иначе неявно все конструкторы super class называются untill object class.


в конструкторах подклассов по умолчанию есть вызов super() по умолчанию.

 //Default constructor of subClass
    subClass() {
    super();
    }

"Если конструктор явно не вызывается конструктор суперкласса, компилятор Java автоматически вставляет вызов конструктора без параметров суперкласса. Если у суперкласса нет конструктора без аргументов, вы получите ошибку времени компиляции. У Object есть такой конструктор, поэтому, если Object является единственным суперклассом, проблем нет."
(источник: https://docs.oracle.com/javase/tutorial/java/IandI/super.html)


Я постараюсь ответить на это с другой точки зрения.

предположим, что Java не вызывала супер конструктор для вас автоматически. Если вы наследуете класс, вам придется либо вызвать супер конструктор неявно, либо переписать его самостоятельно. Это потребует от вас внутренних знаний о том, как работает супер класс, что плохо. Также потребуется переписать код, что тоже нехорошо.

Я согласен с тем, что вызов супер конструктора за сцены немного неинтуитивны. С другой стороны, я не уверен, как они могли сделать это более интуитивно.


Как мы знаем, переменные-члены (поля)класса должны быть инициализированы перед созданием объекта, потому что эти поля представляют состояние объекта. Если эти поля явно не инициализированы, компилятор неявно предоставляет им значения по умолчанию, вызывая конструктор по умолчанию без аргументов. Вот почему конструктор подкласса вызывает конструктор по умолчанию super class no-argument или неявно вызывается компилятором .Компилятор не предоставляет значения по умолчанию для локальных переменных.


здесь ваш расширяющий тест на ваш класс test1 означает, что u может получить доступ ко всем методам и переменной теста в вашем test1. обратите внимание, что u может получить доступ к методам класса или переменной только в том случае ,если ему выделена память, и для этого ему нужен какой-либо конструктор по умолчанию или параметризованный, поэтому здесь компилятор обнаруживает, что он расширяет класс, он попытается найти конструктор супер класса, чтобы u мог получить доступ ко всем своим методам.


Родители Выходят Первыми!! И как в реальном мире ребенок не может существовать без родителей.. Поэтому инициализация родителей(суперкласс) сначала важна для использования thrm в классах детей (подкласс)..