Наследование в Java - создание объекта подкласса также вызывает конструктор суперкласса. Почему именно? - PullRequest
23 голосов
/ 28 января 2009

У меня есть вопрос о наследовании в Java.

У меня есть два класса A и B, и класс B, наследует от A:

public class A {
     public A() {
         System.out.println("Hi!");
     }
}


public class B extends A {
     public B() {
         System.out.println("Bye!");
     }

     public static void main(String[] args) {
         B b = new B();
     }
}

Когда я запускаю программу B, вывод:

Hi!
Bye!

Вопрос : почему конструктор из class A вызывается, когда я создаю объект class B?

Я знаю, что B наследует все от A - все переменные экземпляра или класса и все методы, и в этом смысле объект B имеет все характеристики A плюс некоторые другие характеристики, определенные в B. Однако я не знал и не думал, что когда я создаю объект типа B, конструктор A также вызывается. Итак, написание этого:

B b = new B();

создает Два объекта - один типа B и один типа A .

Становится интересно,

Может кто-нибудь объяснить, почему именно это происходит?

Ответы [ 15 ]

29 голосов
/ 28 января 2009

Он не создает два объекта, только один: B .

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

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

Ваш подкласс на самом деле выглядит так после того, как компилятор вставил супер-вызов:

public class B extends A {
    public B() {
        super();
        System.out.println("Bye!");
    }
}
16 голосов
/ 28 января 2009

Он не создает 2 объекта, он только создает один экземпляр B. Причина, по которой вызывается конструктор суперкласса, заключается в том, что, как вы сказали, B имеет все поля A, и эти поля должны быть инициализированы .

6 голосов
/ 28 января 2009

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

Кроме того, подумайте о том, что произойдет, если ваш подкласс зависит от некоторого внутреннего состояния базового класса. Разве вы не хотите, чтобы экземпляр базового класса был инициализирован тогда?

3 голосов
/ 28 января 2009

Это сделано потому, что конструктор используется для инициализации объекта. Поскольку B также является A, сначала вызывается конструктор для A, а затем конструктор для B.

В качестве примечания вы можете использовать super(arg1, etc), чтобы выбрать, какой конструктор A вызывается на основе передаваемых вами типов параметров ... но это должна быть первая строка в конструкторе.

2 голосов
/ 28 января 2009

Он не создает два объекта, он просто создает один объект b. b имеет тип B и тип A. Конструктор в основном говорит здесь, что вам нужно сделать, чтобы построить меня. Поэтому, когда вы создаете новый экземпляр «B», вы создаете объект, который является одновременно B () и A (). Представьте себе следующий сценарий:

class Q {
  int i;
  public Q() {
    // set default value
    i= 99;
  }
}

class Z extends Q {
  public Z() {
  }
}

Если конструктор для Q НЕ БЫЛ вызван, как мне получить его значение по умолчанию?

1 голос
/ 05 октября 2012

Когда создается новый объект (B), внутри B Объект создается (из-за расширенных ключевых слов). В классе B JVM ищет конструктор класса B, но из-за расширенных ключевых слов переходит в конструктор суперкласса. внутри Значение класса x инициализируется. Но x является приватным, так что мы можем получить доступ к внешнему методу throw getXxx() и получить результат.

1 голос
/ 28 января 2009

Конструктор класса является очень важной концепцией в большинстве ООП

Классы, предоставляя состояние и средства для манипулирования этим состоянием, позволяют легче поддерживать инварианты. Роль конструкторов состоит в том, чтобы привести класс в состояние, соответствующее этим инвариантам (или выбрасывающим, таким образом, запрещающее использование объекта invliad). это несколько слабее, чем предполагалось во многих языках, так как конструктору разрешено передавать свою собственную ссылку "this" в другом месте, но это по крайней мере находится под контролем класса (поэтому он может знать, что он находится в достаточно стабильном и допустимом состоянии чтобы оно было доступно остальному миру)

Наследование делает этот комплекс сложным, поскольку B является -A в очень реальном смысле и, следовательно, может вызывать любой из методов, предоставляемых A. Поэтому части B, которые являются A, должны получить возможность инициализировать себя, прежде чем B получит взгляд в, таким образом, конструктор для A вызывается до того, как начинается настоящая работа конструктора B.

1 голос
/ 28 января 2009

Создание B не создает дополнительного A.

Но, создавая B, вы создаете вид A, потому что B - это A.

Java / C ++ вызывает конструктор A для вас неявно. Зачем? Языковой дизайн. Но делать это хорошо, потому что конструктор A может содержать некоторые инициализации. А поскольку B использует все функции и ошибки A, эти функции лучше правильно инициализировать.

1 голос
/ 28 января 2009

Создан только один объект, оба подрядчика работают на одном и том же объекте.

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

например:

public class A {
     public A() {
        x = 1;
     }
     private int x;
     public int getX() {
        return x;
     }
}


public class B extends A {
     public B() {
     }

     public static void main(String[] args) {
         B b = new B();
         System.out.println(b.getX()); // should print 1 
     }
}
1 голос
/ 28 января 2009

Конструктор содержит всю инициализацию для A. Вы не создаете два объекта. Вы создаете один объект, затем запускаете инициализатор для суперкласса, чтобы инициализировать его члены, и затем запускаете инициализатор для производного класса, чтобы инициализировать его члены.

...