在C++中,你可以在构造函数开始运行之前使用初始化列表来初始化类的字段。例如:
Foo::Foo(string s, double d, int n) : name(s), weight(d), age(n) {
// Empty; already handled!
}
我很好奇为什么Java没有类似的特性。根据 * Core Java:第1卷 *:
C使用这种特殊的语法来调用字段构造函数。在Java中,不需要它,因为对象没有子对象,只有指向其他对象的指针。
以下是我的问题:
1.他们所说的"因为对象没有子对象"是什么意思?我不明白什么是子对象(我试着去查了一下);它们是指子类的示例化来扩展超类吗?
1.至于为什么Java没有像C那样的初始化列表,我认为原因是因为Java默认情况下所有字段都已经初始化了,而且Java使用了super
关键字来调用super(或C++术语中的base)类构造函数,这对吗?
3条答案
按热度按时间44u64gxh1#
在C中,初始化器列表是必需的,因为有一些语言特性在Java中不存在,或者在Java中工作方式不同:
1.* * 一月一日**:在C中,您可以定义标记为
const
的字段,这些字段不能赋值,必须在初始化列表中初始化。Java确实有final
字段,但您可以在构造函数的主体中赋值给final
字段。在C中,在构造函数中赋值给const
字段是非法的。1.* * 参考文献**:C中的引用(相对于指针)必须被初始化才能绑定到某个对象。没有初始化式就创建引用是非法的。在C中,指定它的方法是使用初始化式列表,因为如果你在构造函数体中引用引用而没有首先初始化它,你将使用一个未初始化的引用。在Java中,对象引用的行为类似于C指针,可以在创建后赋值给。否则,它们只是默认为
null
。1.* * 直接子对象**。在C中,对象可以直接包含作为字段的对象,而在Java中,对象只能包含对这些对象的 * 引用 *。也就是说,在C中,如果您声明一个包含
string
作为成员的对象,则该字符串的存储空间将直接构建到对象本身的空间中。而在Java中,你只需要为存储在其他地方的String
对象的引用获取空间。因此,C需要提供一种方法来为这些子对象赋予初始值,否则它们将保持未初始化状态。默认情况下,它使用这些类型的默认构造函数。但是如果你想使用不同的构造函数或者没有默认的构造函数,初始化器列表会给你一个方法来绕过这个问题,在Java中,你不需要担心这个问题,因为引用默认为null
,然后你可以赋值给它们去引用你真正想让它们引用的对象,如果你想使用非默认的构造函数,那么你不需要任何特殊的语法只需设置对通过适当的构造函数初始化的新对象的引用。在Java可能需要初始化列表的少数情况下(例如,调用超类构造函数或为其字段提供默认值),这是通过另外两个语言特性来处理的:调用超类构造函数的
super
关键字,以及Java对象可以在声明它们的时候给它们的字段默认值的事实。由于C有多重继承,只有一个super
关键字不会明确地引用一个基类,在C11之前,C不支持类中的默认初始化器,而必须依赖于初始化器列表。m1m5dgzv2#
** C++ **
两者之间是有区别的
以及
后者不需要初始化(设置为NULL),而前者需要,把它看作一个整数,你不能有一个没有值的int,但是你可以有一个没有值的int指针。
因此,当您具有:
然后是宣言:
自动在
value
中创建OtherClass
的示例。因此,如果OtherClass
具有初始化,则必须在ClassType
构造函数中完成。但是,reference
只是一个指针(内存中的地址),可以保持未初始化状态。如果需要OtherClass
的示例,则必须使用** java **
只有
这相当于C++中的指针。在这种情况下,当您这样做时:
我们不会自动创建
OtherClass
的示例,因此,除非您愿意,否则不必初始化构造函数中的任何内容。当您需要OtherClass
的对象时,可以使用tquggr8v3#
因为Java不需要它们来初始化类型没有零值的字段。
在C++中
如果没有
d
的成员初始化器,D::D()
将被调用,这使得在D
没有零类型时无法初始化字段。当D::D()
被显式声明为private
时,会发生这种情况。在Java中,所有引用类型都有一个已知的零值
null
,因此字段总是可以初始化的。Java也做了大量的工作来确保 * 所有
final
字段在第一次使用之前和构造函数结束之前都被初始化,所以尽管Java有一个类似C++的const
字段初始化需求,但它只是在构造函数体中重载this.fieldName = <expression>
来表示字段初始化。