Наследование в Java - создание объекта подкласса также вызывает конструктор суперкласса. Почему именно?
У меня есть вопрос о наследовании в 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 ответов
Он не создает два объекта, только один: B.
При наследовании от другого класса вы должны вызывать super() в своем конструкторе. Если вы этого не сделаете, компилятор вставит этот вызов для вас, как вы можете видеть.
Конструкторы суперкласса вызываются потому, что в противном случае объект остался бы в неинициализированном состоянии, возможно, без ведома разработчика подкласса.
Ваш подкласс на самом деле выглядит так после того, как компилятор вставил супер вызов:
public class B extends A {
public B() {
super();
System.out.println("Bye!");
}
}
Он не создает 2 объекта, он только создает один экземпляр B. Причина, по которой вызывается конструктор суперкласса, заключается в том, что, как вы сказали, B имеет все поля A, и эти поля необходимо инициализировать.
Помните, что наследование - это отношение "есть" между базовым классом и подклассом, таким образом, каждый раз, когда у вас есть экземпляр подкласса, по определению у вас также будет экземпляр базового класса (как часть экземпляра, а не как два отдельные случаи). Для правильной инициализации базового класса вызывается конструктор.
Кроме того, подумайте о том, что произойдет, если ваш подкласс зависит от некоторого внутреннего состояния базового класса. Разве вы не хотите, чтобы экземпляр базового класса был инициализирован тогда?
Это сделано потому, что конструктор используется для инициализации объекта. Поскольку B также является A, сначала вызывается конструктор для A, а затем конструктор для B.
В качестве примечания вы можете использовать super(arg1, etc)
выбрать, какой конструктор A вызывается на основе типов параметров, которые вы передаете... но это должна быть первая строка в конструкторе.
Он не создает два объекта, он просто создает один объект 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 не был вызван, как бы я получить его значение по умолчанию?
Конструктор содержит всю инициализацию для A. Вы не создаете два объекта. Вы создаете один объект, затем запускаете инициализатор для суперкласса, чтобы инициализировать его члены, и затем запускаете инициализатор для производного класса, чтобы инициализировать его члены.
Конструктор класса является очень важной концепцией в большинстве ООП
Классы, предоставляя состояние и средства управления этим состоянием, позволяют легче поддерживать инварианты. Роль конструкторов состоит в том, чтобы привести класс в состояние, соответствующее этим инвариантам (или выбрасывающим, таким образом, запрещающее использование объекта invliad). это несколько слабее, чем предполагалось во многих языках, так как конструктору разрешено передавать свою собственную ссылку "this" в другом месте, но это по крайней мере находится под контролем класса (поэтому он может знать, что он находится в достаточно стабильном и допустимом состоянии чтобы оно было доступно остальному миру)
Наследование делает этот комплекс сложным, так как B является -A A в очень реальном смысле и, таким образом, может вызывать любой из методов, предоставляемых A. Поэтому части B, которые являются A, должны получить возможность инициализировать себя, прежде чем B увидит, таким образом конструктор для A вызывается до начала реальной работы конструктора B.
Создание B не создает дополнительный A.
Но, создавая B, вы создаете вид A, потому что B - это A.
Java / C++ вызывает конструктор A для вас неявно. Зачем? Языковой дизайн. Но делать это хорошо, потому что конструктор A может содержать некоторые инициализации. А поскольку B использует все функции и ошибки A, эти функции лучше правильно инициализировать.
Создан только один объект, оба подрядчика работают на одном и том же объекте.
Причина проста, как вы знаете, 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
}
}
Когда новый объект создается (B), внутри объекта B A создается (из-за расширенных ключевых слов) . В классе B JVM ищет конструктор класса B, но из-за расширенных ключевых слов переходит в конструктор суперкласса. внутри Значение класса x инициализируется. Но x является частным, так что мы можем получить доступ к внешнему классу throw getXxx()
метод и получить результат.
Если A инициализирует членов в своем конструкторе, и вы забудете вызвать super в своем производном классе, тогда члены A могут быть в плохом состоянии. Ява пытается помешать вам выстрелить себе в ногу.
В Java, когда вы создаете объект дочернего класса, всегда вызывается конструктор родительского класса, потому что класс Object является родителем каждого суперкласса, а когда вы вызываете конструктор класса Object, создается только ваш объект, а java не поддерживает множественное наследование. в случае с классом, если вы расширяете любой другой класс, то связь между вашим дочерним классом и классом Object осуществляется через класс Parent, поэтому для вызова конструктора класса Object должен быть вызван конструктор класса Parent.
Когда объект подкласса создается, то внутренне он не был создан для объекта суперкласса. Но память должна быть выделена для членов суперкласса.
У каждого суперкласса есть конструктор, и каждый конструктор вверх по иерархии запускается во время создания объекта подкласса.
Если объект суперкласса не создан, то как подкласс обращается к нестатическим методам и переменным суперкласса.
Я изучал, что нестатические методы и переменные могут быть доступны только через объекты.