为什么 Java 没有 C++ 中的初始化列表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7154654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't Java have initializer lists like in C++?
提问by Jesse Good
In C++, you can use an initializer list to initialize the class's fields before the constructor begins running. For example:
在 C++ 中,您可以使用初始化列表在构造函数开始运行之前初始化类的字段。例如:
Foo::Foo(string s, double d, int n) : name(s), weight(d), age(n) {
// Empty; already handled!
}
I am curious why Java does not have a similar feature. According to Core Java: Volume 1:
我很好奇为什么 Java 没有类似的功能。根据Core Java:第 1 卷:
C++ uses this special syntax to call field constructors. In Java, there is no need for it because objects have no subobjects, only pointers to other objects.
C++ 使用这种特殊语法来调用字段构造函数。在 Java 中,不需要它,因为对象没有子对象,只有指向其他对象的指针。
Here are my questions:
以下是我的问题:
What do they mean by "because objects have no subobjects?" I don't understand what a subobject is (I tried looking it up); do they mean an instantiation of a subclass which extends a superclass?
As for why Java does not have initializer lists like C++, I would assume that the reason is because all fields are already initialized by default in Java and also because Java uses the
super
keyword to call the super(or base in C++ lingo)-class constructor. Is this correct?
“因为对象没有子对象”是什么意思?我不明白子对象是什么(我试着查了一下);它们是指扩展超类的子类的实例化吗?
至于为什么Java没有像C++这样的初始化列表,我认为原因是因为Java中所有字段都已经默认初始化了,而且Java使用
super
关键字来调用super(或C++行话中的base)类构造函数. 这个对吗?
回答by templatetypedef
In C++, initializer lists are necessary because of a few language features that are either not present in Java or work differently in Java:
在 C++ 中,初始化列表是必要的,因为一些语言特性要么在 Java 中不存在,要么在 Java 中工作方式不同:
const
: In C++, you can define a fields that are markedconst
that cannot be assigned to and must be initialized in the initializer list. Java does havefinal
fields, but you can assign tofinal
fields in the body of a constructor. In C++, assigning to aconst
field in the constructor is illegal.References: In C++, references (as opposed to pointers) must be initialized to bind to some object. It is illegal to create a reference without an initializer. In C++, the way that you specify this is with the initializer list, since if you were to refer to the reference in the body of the constructor without first initializing it you would be using an uninitialized reference. In Java, object references behave like C++ pointers and can be assigned to after created. They just default to
null
otherwise.Direct subobjects. In C++, an object can contain object directly as fields, whereas in Java objects can only hold referencesto those objects. That is, in C++, if you declare an object that has a
string
as a member, the storage space for that string is built directly into the space for the object itself, while in Java you just get space for a reference to some otherString
object stored elsewhere. Consequently, C++ needs to provide a way for you to give those subobjects initial values, since otherwise they'd just stay uninitialized. By default it uses the default constructor for those types, but if you want to use a different constructor or no default constructor is available the initializer list gives you a way to bypass this. In Java, you don't need to worry about this because the references will default tonull
, and you can then assign them to refer to the objects you actually want them to refer to. If you want to use a non-default constructor, then you don't need any special syntax for it; just set the reference to a new object initialized via the appropriate constructor.
const
: 在C++中,可以const
在初始化列表中定义一个标记为不能赋值且必须初始化的字段。Java 确实有final
字段,但您可以final
在构造函数的主体中分配字段。在 C++ 中,分配给const
构造函数中的字段是非法的。引用:在 C++ 中,引用(与指针相对)必须被初始化以绑定到某个对象。创建没有初始化程序的引用是非法的。在 C++ 中,您指定它的方式是使用初始化列表,因为如果您要引用构造函数主体中的引用而不先初始化它,您将使用未初始化的引用。在 Java 中,对象引用的行为类似于 C++ 指针,可以在创建后赋值。他们只是默认为
null
其他方式。直接子对象。在 C++ 中,对象可以直接包含对象作为字段,而在 Java 中对象只能保存对这些对象的引用。也就是说,在 C++ 中,如果你声明一个对象
string
作为成员,那么该字符串的存储空间将直接构建到对象本身的空间中,而在 Java 中,你只是获得了对其他对象的引用的空间String
对象存储在别处。因此,C++ 需要为您提供一种方法来为这些子对象赋予初始值,否则它们将保持未初始化状态。默认情况下,它为这些类型使用默认构造函数,但如果您想使用不同的构造函数或没有可用的默认构造函数,则初始化列表为您提供了一种绕过此方法的方法。在 Java 中,您无需担心这一点,因为引用将默认为null
,然后您可以将它们分配给您实际希望它们引用的对象。如果要使用非默认构造函数,则不需要任何特殊语法;只需将引用设置为通过适当的构造函数初始化的新对象。
In the few cases where Java might want initializer lists (for example, to call superclass constructors or give default values to its fields), this is handled through two other language features: the super
keyword to invoke superclass constructors, and the fact that Java objects can give their fields default values at the point at which they're declared. Since C++ has multiple inheritance, just having a single super
keyword wouldn't unambiguously refer to a single base class, and prior to C++11 C++ didn't support default initializers in a class and had to rely on initializer lists.
在 Java 可能需要初始化列表的少数情况下(例如,调用超类构造函数或为其字段提供默认值),这是通过另外两个语言特性处理的:super
调用超类构造函数的关键字,以及 Java 对象可以在声明时为其字段提供默认值。由于 C++ 具有多重继承,因此仅具有单个super
关键字不会明确引用单个基类,并且在 C++11 之前,C++ 不支持类中的默认初始化器,而不得不依赖初始化器列表。
Hope this helps!
希望这可以帮助!
回答by George
C++
C++
There is a difference between
之间有区别
ClassType t(initialization arguments);
and
和
ClassType * pt;
The latter doesn't need to be initialized (set to NULL). The former does. Think of it as an integer. You can't have an int without a value, BUTyou can have an int pointer without a value.
后者不需要初始化(设置为 NULL)。前者可以。把它想象成一个整数。你不能有一个没有值的 int,但你可以有一个没有值的 int 指针。
So when you have:
所以当你有:
class ClassType
{
OtherClass value;
OtherClass * reference;
};
Then the declaration:
然后声明:
ClassType object;
automatically creates an instance of OtherClass
in value
. Therefore, if OtherClass
has initialization, it must be done in the ClassType
constructor. However, reference
is just a pointer (address in memory) and can remain uninitialized. If you want an instance of OtherClass
you must use
自动创建OtherClass
in的实例value
。因此,如果OtherClass
有初始化,则必须在ClassType
构造函数中完成。但是,reference
它只是一个指针(内存中的地址)并且可以保持未初始化状态。如果你想要一个OtherClass
你必须使用的实例
object.reference = new OtherClass(initialization arguments);
Java
爪哇
There is only
只有
class ClassType
{
OtherClass reference;
}
This is equivalent to a pointer in C++. In this case when you do:
这相当于 C++ 中的指针。在这种情况下,当您执行以下操作时:
ClassType object = new ClassType();
You don't automatically create an instance of OtherClass
. Therefore, you don't have to initialize anything in the constructor unless you want to. When you want an object of OtherClass
you can use
您不会自动创建OtherClass
. 因此,除非您愿意,否则不必在构造函数中初始化任何内容。当你想要一个对象时,OtherClass
你可以使用
object.reference = new OtherClass();
回答by Mike Samuel
Because Java does not need them to allow initialization of fields whose type has no zero-value.
因为 Java 不需要它们来允许类型没有零值的字段的初始化。
In C++
在 C++ 中
class C {
D d;
}
without a member initializer for d
, D::D()
will be called which makes it impossible to initialize the field if there is no zero-type for D
. This can happen when D::D()
is explicitly declared private
.
如果没有成员初始值设定项 for d
,D::D()
将被调用,如果没有零类型 for ,则无法初始化该字段D
。这可能在D::D()
显式声明时发生private
。
In Java, there is a known zero-valuefor all reference types, null
, so a field can always be initialized.
在 Java 中,所有引用类型都有一个已知的零值null
,因此始终可以初始化字段。
Java also does a bunch of work to make sure* that all final
fields are initialized before first use and before the constructor ends, so while Java has a requirement like C++'s const
field initialization requirement, it just overloads this.fieldName = <expression>
in the constructor body to mean field initialization.
Java 还做了大量工作来确保*所有final
字段在第一次使用之前和构造函数结束之前都已初始化,因此虽然 Java 有像 C++ 的const
字段初始化要求一样的要求,但它只是this.fieldName = <expression>
在构造函数体中重载以表示字段初始化。
- : modulo exceptions thrown in the ctor, overridden method calls from the base class, etc.
- : ctor 中抛出的模异常,来自基类的覆盖方法调用等。