Java中的继承-创建子类的对象也会调用超类的构造函数。到底为什么?

Java中的继承-创建子类的对象也会调用超类的构造函数。到底为什么?,java,inheritance,constructor,subclass,Java,Inheritance,Constructor,Subclass,我有一个关于Java继承的问题 我有两个类A和B,B类继承自A: 当我运行程序B时,输出为: Hi! Bye! 问题:当我创建类B的对象时,为什么调用类A的构造函数 我知道B继承了A的所有内容—所有实例或类变量,以及所有方法,从这个意义上说,B的对象具有A的所有特征以及B中定义的一些其他特征。然而,我不知道,也没有想到,当我创建B类型的对象时,A的构造函数也会被调用。 因此,写下以下内容: B b = new B(); 创建两个对象-一个为B类型,另一个为A类型 这越来越有趣了 有人能解释一

我有一个关于Java继承的问题

我有两个类A和B,B类继承自A:

当我运行程序B时,输出为:

Hi!
Bye!
问题:当我创建类B的对象时,为什么调用类A的构造函数

我知道B继承了A的所有内容—所有实例或类变量,以及所有方法,从这个意义上说,B的对象具有A的所有特征以及B中定义的一些其他特征。然而,我不知道,也没有想到,当我创建B类型的对象时,A的构造函数也会被调用。 因此,写下以下内容:

B b = new B();
创建两个对象-一个为B类型,另一个为A类型

这越来越有趣了


有人能解释一下为什么会这样吗

记住继承是基类和子类之间的关系,因此每次有子类的实例时,根据定义,基类的实例也将作为实例的一部分,而不是作为两个单独的实例。要正确初始化基类,将调用构造函数


此外,考虑一下如果子类依赖于基类的某些内部状态,会发生什么情况。那么您不想初始化基类的实例吗

它不创建2个对象,只创建一个B实例。调用超类构造函数的原因是,正如您所说,B拥有A的所有字段,这些字段需要初始化。

它不创建两个对象,只有一个:B

从另一个类继承时,必须在构造函数中调用super。如果您不这样做,编译器将为您插入调用,您可以清楚地看到

调用超类构造函数是因为否则对象将处于未初始化状态,子类的开发人员可能不知道

编译器插入超级调用后,您的子类实际上如下所示:

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

如果A初始化其构造函数中的成员,而您忘记在派生类中调用super,则A的成员可能处于错误状态。Java正试图阻止您自食其果。

构造函数包含A的所有初始化。您没有创建两个对象。您正在创建一个对象,然后运行超类的初始值设定项来初始化其成员,然后运行派生类的初始值设定项来初始化其成员。

它不创建两个对象,只创建一个对象b。b是类型b和类型A。构造函数基本上是说,这里是构造我所需要做的。因此,当您创建一个新的B实例时,您正在构建一个既是a又是B的对象。想象一下以下场景:

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

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

如果没有调用Q的构造函数,如何获取其默认值?

只创建一个对象,两个contractor在同一个对象上运行

原因很简单,正如你所知道的,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也是A,它首先调用A的构造函数,然后调用B的构造函数


作为旁注,您可以使用superarg1等根据传递的参数类型选择调用的构造函数。。。但它必须是构造函数中的第一行。

创建B不会创建额外的A

但是通过创造B,你创造了一种a,因为B是a


Java/C++隐式调用一个函数的构造函数。为什么?语言设计。但是这样做很好,因为的构造函数可能包含一些初始化。由于B使用了A的所有特性和bug,因此最好正确初始化这些特性。

类的构造函数在大多数OOP中都是非常重要的概念

类,通过提供状态和操作该状态的方法,允许更容易地维护不变量。构造函数的作用是使类进入符合这些不变量的状态,或抛出,从而禁止使用invliad对象。 这在许多语言中比预期的要宽松一些,因为构造函数可以在其他地方传递自己的“this”引用,但这至少在类的控制下,因为它可以知道它处于足够稳定和有效的状态,以便世界其他地方可以访问它

继承使这一点变得复杂,因为B在非常真实的意义上是a,因此可以调用a提供的任何方法。因此,B中的a部分应该在B进入之前有机会初始化自己,因此在B构造的实际工作之前调用a的构造函数
或开始。

当创建新对象B时,在B内部,使用扩展关键字创建对象B。在B类JVM中搜索B类构造函数,但由于扩展关键字,它会转到超级类构造函数。在类中,初始化x值。但是x是私有的,因此我们可以访问外部类抛出getXxx方法并获得结果。

当创建子类对象时,它在内部不是为超级类对象创建的。但是应该为超级类成员分配内存。

在java中,当您创建子类的对象时,父类的构造函数总是调用对象类是因为对象类是每个超类的父类,当调用对象类的构造函数时,只创建对象,java不支持类的多重继承。因此,如果扩展任何其他类,则子类和对象类之间的关系是通过父类来调用的必须调用对象类的构造函数父类的构造函数。

如果未创建超类对象,则子类如何访问超类非静态方法和变量


我研究了非静态方法和变量只能通过对象访问。

每个超类都有一个构造函数,层次结构上的每个构造函数在创建子类的对象时运行。

它不是两个对象。如果你用语言来表达,B是A,汽车是汽车。它不是2个对象。类A需要一个初始化自己的机会。我认为这里的基本误解是调用super是否正在创建一个新对象。事实并非如此。
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 
     }
}