java继承和对象创建
基类:
public class Inheritance {
int i;
Inheritance() {
System.out.println("I am in base class" + i);
}
}
派生类:
public class TestInheritance extends Inheritance {
TestInheritance() {
System.out.println("I am in derived class");
}
public static void main(String[] args) {
TestInheritance obj = new TestInheritance();
}
}
这就是我对上面发生的事情的想法
默认情况下,当我创建派生类的对象时,将调用super()
,并调用基类的构造函数,然后初始化变量i
现在,我的问题是:在这种情况下,构造函数是否只初始化变量i
,而不创建类的具体对象
从我所读到的到目前为止,只创建了一个派生类的对象,其中包含i
变量
但是从调用基类的构造函数到调用派生类的构造函数的时间点i
是如何存储在内存中的
基类是抽象类的情况又会怎样呢强>
如果我能知道在不同的时间点在记忆中发生了什么,我将不胜感激
如果我说了一些根本不正确的话,请告诉我。我真的很想知道这是怎么回事
# 1 楼答案
物理上创建了一个对象,但概念上创建了2个。这就像,比方说,一个女婴出生的时候:从身体上来说,她只是一个,但从概念上来说,一个新的女性出生了,一个新的人类出生了,一个新的有知觉的人出生了,一个新的地球居民出生了,等等。是的,没错。这里也有一种继承关系(子类型),我是故意这么做的。为了避免混淆,最好说只有一个对象有几个方面;同时是不同(超级)类成员的一个对象
现在,逻辑部分已经讲够了,让我们来检查物理部分。单个(物理)对象在内存中使用以下结构创建
第一部分(B)包含从C的超类B继承的所有字段(如果有)。第二部分(C',我使用
'
表示“补码”)包含所有C的“专有”字段(即不是从B继承的,而是在C本身中定义的)。需要注意的是,创建的对象不是从C'开始,而是从B'开始。构成完整对象的是继承字段和新字段的组合现在,如果B有自己的超类A,结构会是这样的:
这里需要注意的是
B == A + B'
。换句话说,C不需要了解A。它只关心它的直接超类B,它隐藏了它的内部结构回答具体问题:
与上面的A、B和C在结构上链接的方式相同,它们也在初始化期间链接。如果不是这样的话,就好像我最初的例子中的女孩出生时没有我们所知道的任何其他东西一样根据定义,她也是。这是不可能的。完全矛盾。因此,执行两个类的构造过程,其中包括:初始化“零”值中的字段(
null
用于引用,false
用于boolean
),并执行一个构造函数(可以调用其他构造函数)在这种特殊情况下,字段
i
被初始化,一个Inheritance
构造函数被执行,TestInheritance
的字段(如果有)将被初始化,然后一个TestInheritance
的构造函数将被执行。我们如何确切地说出每个类的构造函数?相对简单。引发一切的是new TestInheritance()
。这显然表明TestInheritance
的构造函数没有任何参数(该参数存在;否则将出现编译错误)。但是,此构造函数没有显式调用超类的任何构造函数(通过关键字super(...)
)。正如我们在上面看到的,这是不可能的,编译器会自动插入super()
的等价物,即不带参数(Inheritance()
)的超类构造函数调用。同样,这个构造函数存在,并且一切都很好。产出将是:没有参数的构造函数称为“默认构造函数”,主要原因有三: -它们通常非常简单,因为它们没有参数。 -当子类的构造函数没有显式调用任何supeclass构造函数时,会自动调用它们。 -它们是为这些类自动提供的,而不需要程序员编写任何显式构造函数。在这种情况下,构造函数什么也不做,只进行初始化
这并不完全正确。实际上,只创建了一个对象,但它对应于与
new
(TestInheritance
)一起使用的类,在本例中,该类碰巧没有字段,但这与此无关。实际上,两个输出行都是打印的。概念上。。。我们已经提到了当执行
new TestInheritance()
时,在调用构造函数之前,甚至在初始化之前发生的第一件事执行的操作是为整个对象分配内存。 -通常这个内存是“脏的”,这就是为什么它需要初始化。 -有空间存放TestInheritance
的字段、它的超类字段等等。甚至内存中对象中每个字段的位置都是预先知道的因此,即使在调用基类的构造函数之前,已经为
i
和任何其他字段分配了内存,只是它们是“脏的”(未初始化)没有区别。唯一的一点是,您不能自己创建抽象类的对象。您可以将它们创建为(具体)子类的一部分。这类似于一个新的人类不能由他/她自己出生的事实。不是女婴就是男婴
我希望我做到了
没有什么“根本不正确”
# 2 楼答案
我认为这是一个常见的关于继承的困惑。你似乎已经明白,只有一个物体被创造出来,这是正确的
我建议您将基类中的实例变量视为包含在任何超类中,就像基类中的任何公共或受保护方法都可以从超类访问一样
当一个对象被实例化时,java运行时会做它需要做的事情,为大部分实例变量所需要的所有东西分配存储。因此,基类中的实例变量可以看作是包含对象的所有实例变量的内存块的一部分,不管它们是在子类还是在超类中声明的
还有一个术语更正:在您的代码中,变量没有显式地“初始化”,我想您要问的是“分配”,即变量在内存中的空间在什么位置。“Initialize”意味着变量已经被赋予了一个值,尽管Java在为其变量分配默认值方面做得非常好,但我认为在这种情况下,您可以选择分配