为什么Java没有像C++那样的初始值设定项列表?

在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. “因为对象没有子对象”是什么意思?我不明白什么是子对象(我试图查找它);它们是否意味着扩展超类的子类的实例化?

  2. 至于为什么Java没有像C++那样的初始值设定项列表,我认为原因是因为所有字段在Java中都已经默认初始化,并且还因为Java使用关键字来调用super(或C++术语中的base)类构造函数。这是正确的吗?super


答案 1

在C++中,初始值设定项列表是必需的,因为一些语言功能要么在 Java 中不存在,要么在 Java 中以不同的方式工作:

  1. const:在C++中,可以定义一个已标记的字段,这些字段不能分配给初始值设定项列表,并且必须在初始值设定项列表中进行初始化。Java 确实有字段,但您可以分配给构造函数正文中的字段。在C++中,在构造函数中分配字段是非法的。constfinalfinalconst

  2. 引用:在C++中,必须初始化引用(而不是指针)以绑定到某个对象。创建没有初始值设定项的引用是非法的。在C++中,指定此项的方式是使用初始值设定项列表,因为如果要在构造函数主体中引用引用而不首先对其进行初始化,则将使用未初始化的引用。在 Java 中,对象引用的行为类似于C++指针,可以在创建后将其赋值。他们只是默认为其他方式。null

  3. 直接子对象。在C++中,对象可以直接包含作为字段的对象,而在 Java 中,对象只能包含对这些对象的引用。也就是说,在C++,如果您声明一个具有作为成员的对象,则该字符串的存储空间直接内置到对象本身的空间中,而在Java中,您只需获得对存储在其他位置的其他对象的引用的空间。因此,C++需要提供一种方法来为这些子对象提供初始值,否则它们将保持未初始化状态。默认情况下,它使用这些类型的默认构造函数,但是如果要使用其他构造函数或没有可用的默认构造函数,则初始值设定项列表为您提供了一种绕过此问题的方法。在 Java 中,您不必担心这一点,因为引用将默认为 ,然后您可以指定它们来引用您实际希望它们引用的对象。如果你想使用非默认构造函数,那么你不需要任何特殊的语法;只需设置对通过适当的构造函数初始化的新对象的引用。stringStringnull

在 Java 可能需要初始值设定项列表的少数情况下(例如,调用超类构造函数或为其字段提供默认值),这是通过另外两种语言功能处理的:用于调用超类构造函数的关键字,以及 Java 对象可以在声明时为其字段提供默认值的事实。由于C++具有多重继承,因此仅具有单个关键字不会明确引用单个基类,并且在C++11之前,C++不支持类中的默认初始值设定项,并且必须依赖于初始值设定项列表。supersuper

希望这有帮助!


答案 2

C++

有区别

ClassType t(initialization arguments);

ClassType * pt;

后者不需要初始化(设置为 NULL)。前者确实如此。可以将其视为整数。不能有没有值的 int,可以有一个没有值的 int 指针。

因此,当您拥有:

class ClassType
{
    OtherClass value;
    OtherClass * reference;
};

然后声明:

ClassType object;

自动创建 中的 实例。因此,如果具有初始化,则必须在构造函数中完成。但是,它只是一个指针(内存中的地址),可以保持未初始化状态。如果你想要一个实例,你必须使用OtherClassvalueOtherClassClassTypereferenceOtherClass

object.reference = new OtherClass(initialization arguments);

爪哇岛

只有

class ClassType
{
    OtherClass reference;
}

这等效于C++中的指针。在这种情况下,当您执行以下操作时:

ClassType object = new ClassType();

您不会自动创建 的实例。因此,除非您愿意,否则不必在构造函数中初始化任何内容。当你想要一个对象,你可以使用OtherClassOtherClass

object.reference = new OtherClass();