57

在 C++ 中,您可以使用初始化列表在构造函数开始运行之前初始化类的字段。例如:

Foo::Foo(string s, double d, int n) : name(s), weight(d), age(n) {
    // Empty; already handled!
}

我很好奇为什么 Java 没有类似的功能。根据核心 Java:第 1 卷

C++ 使用这种特殊语法来调用字段构造函数。在 Java 中,不需要它,因为对象没有子对象,只有指向其他对象的指针。

以下是我的问题:

  1. “因为对象没有子对象”是什么意思?我不明白什么是子对象(我试着查了一下);它们是指扩展超类的子类的实例化吗?

  2. 至于为什么 Java 没有像 C++ 这样的初始化列表,我认为原因是因为 Java 中默认情况下已经初始化了所有字段,还因为 Java 使用super关键字来调用 super(或 C++ 术语中的 base)-class 构造函数. 它是否正确?

4

3 回答 3

104

在 C++ 中,初始化列表是必要的,因为一些语言特性在 Java 中不存在或在 Java 中以不同的方式工作:

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

  2. 引用:在 C++ 中,引用(相对于指针)必须初始化才能绑定到某个对象。在没有初始化程序的情况下创建引用是非法的。在 C++ 中,您指定它的方式是使用初始化列表,因为如果您要在构造函数主体中引用引用而不首先对其进行初始化,那么您将使用未初始化的引用。在 Java 中,对象引用的行为类似于 C++ 指针,可以在创建后分配。他们只是默认为null其他。

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

在 Java 可能需要初始化列表的少数情况下(例如,调用超类构造函数或为其字段提供默认值),这是通过其他两个语言特性来处理的:super调用超类构造函数的关键字,以及 Java 对象可以在声明它们的时候给它们的字段默认值。由于 C++ 具有多重继承,因此仅使用单个super关键字不会明确引用单个基类,并且在 C++11 之前,C++ 不支持类中的默认初始化程序并且必须依赖初始化程序列表。

希望这可以帮助!

于 2011-08-22T23:15:21.403 回答
10

C++

之间有区别

ClassType t(initialization arguments);

ClassType * pt;

后者不需要初始化(设置为 NULL)。前者可以。把它想象成一个整数。你不能有一个没有值的 int,但是你可以有一个没有值的 int 指针。

所以当你有:

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

然后声明:

ClassType object;

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

object.reference = new OtherClass(initialization arguments);

爪哇

只有

class ClassType
{
    OtherClass reference;
}

这相当于 C++ 中的指针。在这种情况下,当您这样做时:

ClassType object = new ClassType();

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

object.reference = new OtherClass();
于 2011-08-22T23:35:58.173 回答
1

因为 Java 不需要它们来允许初始化类型没有零值的字段。

在 C++ 中

class C {
  D d;
}

没有成员初始化器dD::D()将被调用,如果没有零类型,则无法初始化该字段D。这可能在D::D()显式声明时发生private

在 Java 中,所有引用类型都有一个已知的零值null,因此始终可以初始化字段。

Java 还做了很多工作来确保final在第一次使用之前和构造函数结束之前初始化所有字段,因此虽然 Java 有像 C++ 的const字段初始化要求这样的要求,但它只是this.fieldName = <expression>在构造函数主体中重载以表示字段初始化。

  • :在ctor中抛出的模异常,来自基类的重写方法调用等。
于 2011-08-22T23:13:25.337 回答